plugins/developer-kit-java/skills/unit-test-scheduled-async/SKILL.md
Provides patterns for unit testing Spring `@Scheduled` and `@Async` methods using JUnit 5, CompletableFuture, Awaitility, and Mockito. Covers mocking task execution and timing, verifying execution counts, testing cron expressions, validating retry behavior, and simulating thread pool behavior. Use when testing background tasks, cron jobs, periodic execution, scheduled tasks, or thread pool behavior.
npx skillsauth add giuseppe-trisciuoglio/developer-kit unit-test-scheduled-asyncInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
@Scheduled and @Async MethodsPatterns for unit testing Spring @Scheduled and @Async methods with JUnit 5. Test CompletableFuture results, use Awaitility for race conditions, mock scheduled task execution, and validate error handling — without waiting for real scheduling intervals.
@Scheduled method logic@Async method behaviorCompletableFuture results@Async methods directly — bypass Spring's async proxy; the annotation is irrelevant in unit tests@Mock and @InjectMocks (Mockito)CompletableFuture.get(timeout, unit) or await().atMost(...).untilAsserted(...)@Scheduled methods directly — do not wait for cron/fixedRate; the annotation is ignored in unit testsExecutionException wrapping on CompletableFuture.get()Validation checkpoints:
CompletableFuture.get(), assert the returned value before verifying mock interactionsExecutionException is thrown, check .getCause() to identify the root exceptionatMost() duration or reduce pollInterval() until the condition is reachableverify() callsKey patterns — complete examples in references/examples.md:
// @Async: call directly, wait with CompletableFuture.get(timeout, unit)
@Service
class EmailService {
@Async
public CompletableFuture<Boolean> sendEmailAsync(String to) {
return CompletableFuture.supplyAsync(() -> true);
}
}
@Test
void shouldReturnCompletedFuture() throws Exception {
EmailService service = new EmailService();
Boolean result = service.sendEmailAsync("[email protected]").get(5, TimeUnit.SECONDS);
assertThat(result).isTrue();
}
// @Scheduled: call directly, mock the repository
@Component
class DataRefreshTask {
@InjectMocks private DataRepository dataRepository;
@Scheduled(fixedDelay = 60000) public void refreshCache() { /* ... */ }
}
@Test
void shouldRefreshCache() {
when(dataRepository.findAll()).thenReturn(List.of(new Data(1L, "item1")));
dataRefreshTask.refreshCache();
verify(dataRepository).findAll();
}
// Awaitility: use for race conditions with shared mutable state
@Test
void shouldProcessAllItems() {
BackgroundWorker worker = new BackgroundWorker();
worker.processItems(List.of("item1", "item2", "item3"));
Awaitility.await()
.atMost(Duration.ofSeconds(5))
.pollInterval(Duration.ofMillis(100))
.untilAsserted(() -> assertThat(worker.getProcessedCount()).isEqualTo(3));
}
// Mocked dependencies with exception handling
@Test
void shouldHandleAsyncExceptionGracefully() {
doThrow(new RuntimeException("Email failed")).when(emailService).send(any());
CompletableFuture<String> result = service.notifyUserAsync("user123");
assertThatThrownBy(result::get)
.isInstanceOf(ExecutionException.class)
.hasCauseInstanceOf(RuntimeException.class);
}
Full Maven/Gradle dependencies, additional test classes, and execution count patterns: see references/examples.md.
CompletableFuture.get() to prevent hanging tests@Scheduled logic directly — the annotation is ignored in unit testsCompletableFuture.get()@Async self-invocation: calling @Async from another method in the same class executes synchronously — the Spring proxy is bypassedThreadPoolTaskScheduler does not guarantee execution orderatMost(); infinite waits hang the test suite@Scheduled is ignored in unit tests — call methods directly@Async Documentation@Scheduled Documentationreferences/examples.mddevelopment
Explore codebase before committing to a change. Phase executor skill for specs.explore command.
development
Executes real end-to-end verification against a running application after specification implementation. Detects the application type, starts the local runtime (Docker, Node, Spring Boot, etc.), runs real tests (curl for REST APIs, Playwright for web SPAs, computer-use for desktop apps), verifies acceptance criteria from the functional specification, generates a markdown report, and tears down the environment. Use when: user asks to verify a completed spec with real tests, run e2e checks after implementation, validate acceptance criteria in a live environment, or test the feature for real after task completion.
development
Initialize Spec-Driven Development context — detects tech stack, conventions, architecture patterns, and bootstraps persistence backends. Triggers on 'sdd-init', 'init sdd', 'setup sdd', 'initialize sdd', 'setup project', 'initialize project context'. Creates/updates docs/specs/architecture.md & ontology.md (Constitution), and populates knowledge-graph.json.
development
Optimizes raw idea descriptions into structured prompts ready for the brainstorming workflow. TRIGGER when: user says "optimize for brainstorm", "prepare idea for brainstorm", "enhance this idea", "make this ready for brainstorming", "imposta per brainstorm", or wants to improve a feature idea before using /specs.brainstorm. DO NOT TRIGGER for code optimization, refactoring, or general prompt engineering tasks.