mcpbeat Sign in

Unit Test Scheduled Async Agent Skill

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.

3k tokens
context cost
the whole folder, loaded on every use
2
files
instructions only
0
copies elsewhere
how many repositories repackaged it
316
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-scheduled-async

The instruction itself

9 sections, as written by the author

Unit Testing @Scheduled and @Async Methods

Overview

Patterns 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.

When to Use

  • Testing @Scheduled method logic
  • Testing @Async method behavior
  • Verifying CompletableFuture results
  • Testing async error handling
  • Testing cron expression logic without waiting for actual scheduling
  • Validating thread pool behavior and execution counts
  • Testing background task logic in isolation

Instructions

  • Call @Async methods directly — bypass Spring's async proxy; the annotation is irrelevant in unit tests
  • Mock dependencies with @Mock and @InjectMocks (Mockito)
  • Wait for completion — use CompletableFuture.get(timeout, unit) or await().atMost(...).untilAsserted(...)
  • Call @Scheduled methods directly — do not wait for cron/fixedRate; the annotation is ignored in unit tests
  • Test exception paths — verify ExecutionException wrapping on CompletableFuture.get()

Validation checkpoints:

  • After CompletableFuture.get(), assert the returned value before verifying mock interactions
  • If ExecutionException is thrown, check .getCause() to identify the root exception
  • If Awaitility times out, increase atMost() duration or reduce pollInterval() until the condition is reachable
  • After multiple task invocations, assert execution counts before verify() calls

Examples

Key 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.

Best Practices

  • Always set a timeout on CompletableFuture.get() to prevent hanging tests
  • Mock all dependencies — never call real external services in unit tests
  • Use Awaitility only for race conditions; prefer direct calls for simple async methods
  • Test @Scheduled logic directly — the annotation is ignored in unit tests
  • Assert values before verifying mock interactions; verify after async completion

Common Pitfalls

  • Relying on Spring's async executor instead of calling methods directly
  • Missing timeout on CompletableFuture.get()
  • Forgetting to test exception propagation in async methods
  • Not mocking dependencies that async methods invoke internally
  • Waiting for actual cron/fixedRate timing instead of testing logic in isolation

Constraints and Warnings

  • @Async self-invocation: calling @Async from another method in the same class executes synchronously — the Spring proxy is bypassed
  • Thread pool ordering: ThreadPoolTaskScheduler does not guarantee execution order
  • CompletableFuture chaining: exceptions in intermediate stages can be silently lost — test each stage
  • Awaitility timeout: always set a reasonable atMost(); infinite waits hang the test suite
  • No actual scheduling: @Scheduled is ignored in unit tests — call methods directly

References

Other skills for the same job

different authors, same section of the catalogue
Webapp Testing
by anthropics
vendor ×12

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

6k tokens scripts
Finishing A Development Branch
by ZhanlinCui
×7

Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup

1k tokens
Test Driven Development
by w95
×7

Use when implementing any feature or bugfix, before writing implementation code

2k tokens
Systematic Debugging
by ratacat
×7

Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes

10k tokens scripts
Verification Before Completion
by ZhanlinCui
×6

Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always

1k tokens
Backtest Expert
by BaggaT236
×3

Expert guidance for systematic backtesting of trading strategies. Use when developing, testing, stress-testing, or validating quantitative trading strategies. Covers "beating ideas to death" methodology, parameter robustness testing, slippage modeling, bias prevention, and interpreting backtest results. Applicable when user asks about backtesting, strategy validation, robustness testing, avoiding overfitting, or systematic trading development.

15k tokens scripts
Adaptyv
by christophacham
×3

Cloud laboratory platform for automated protein testing and validation. Use when designing proteins and needing experimental validation including binding assays, expression testing, thermostability measurements, enzyme activity assays, or protein sequence optimization. Also use for submitting experiments via API, tracking experiment status, downloading results, optimizing protein sequences for better expression using computational tools (NetSolP, SoluProt, SolubleMPNN, ESM), or managing protein design workflows with wet-lab validation.

16k tokens
Aeon
by christophacham
×3

This skill should be used for time series machine learning tasks including classification, regression, clustering, forecasting, anomaly detection, segmentation, and similarity search. Use when working with temporal data, sequential patterns, or time-indexed observations requiring specialized algorithms beyond standard ML approaches. Particularly suited for univariate and multivariate time series analysis with scikit-learn compatible APIs.

19k tokens

How to use it

Copy the folder

Take giuseppe-trisciuoglio/unit-test-scheduled-async from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.