
Unit Test Scheduled Async
Write JUnit tests for Spring @Async CompletableFuture flows and scheduled jobs using Awaitility and AssertJ patterns from copy-paste examples.
Overview
Unit Test Scheduled Async is an agent skill for the Ship phase that provides Spring Boot JUnit and Awaitility patterns for testing @Async and scheduled tasks.
Install
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-scheduled-asyncWhat is this skill?
- Maven and Gradle dependency blocks for Spring Boot, JUnit Jupiter, Awaitility, AssertJ
- EmailService-style @Async CompletableFuture unit test pattern
- Examples for verifying async completion without flaky sleeps
- Scheduled task testing patterns (per developer-kit async/scheduled module)
- Spring Boot starter test stack alignment
- 4 listed test dependencies (Spring Boot, JUnit Jupiter, Awaitility, AssertJ)
Adoption & trust: 1.2k installs on skills.sh; 271 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Spring service uses @Async or schedulers but unit tests hang, flake, or never assert completion of background work.
Who is it for?
Java solo builders shipping Spring Boot APIs who want agent-guided async and scheduled test scaffolding.
Skip if: Non-Spring stacks, pure frontend tests, or teams that already enforce a bespoke async test harness with no gap to fill.
When should I use this skill?
User needs Spring async or scheduled unit test examples with Awaitility and JUnit.
What do I get? / Deliverables
You get dependency snippets and test classes that await CompletableFuture results and scheduled behavior with AssertJ-friendly assertions.
- Async unit test class patterns
- Dependency configuration for test scope
- Scheduled/async assertion examples
Recommended Skills
Journey fit
Ship testing is the primary home because the skill delivers test code for async and scheduled Spring behavior before release. testing subphase matches unit/integration examples for CompletableFuture completion and timed async assertions.
How it compares
Copy-paste Spring test recipes—not a full CI pipeline skill or Playwright browser testing package.
Common Questions / FAQ
Who is unit-test-scheduled-async for?
Spring Boot developers and agent-assisted testers who need reliable patterns for async email, notification, or scheduled job unit tests.
When should I use unit-test-scheduled-async?
In Ship testing while adding or fixing coverage for @Async CompletableFuture methods or scheduled tasks before release.
Is unit-test-scheduled-async safe to install?
It supplies test-scope dependencies and example code only; review the Security Audits panel on this page before installing from third-party sources.
SKILL.md
READMESKILL.md - Unit Test Scheduled Async
# Async & Scheduled Testing — Code Examples ## Maven Dependencies ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.awaitility</groupId> <artifactId>awaitility</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <scope>test</scope> </dependency> ``` ## Gradle Dependencies ```kotlin dependencies { implementation("org.springframework.boot:spring-boot-starter") testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.awaitility:awaitility") testImplementation("org.assertj:assertj-core") } ``` ## Basic Async Testing with CompletableFuture ```java @Service public class EmailService { @Async public CompletableFuture<Boolean> sendEmailAsync(String to, String subject) { return CompletableFuture.supplyAsync(() -> { System.out.println("Sending email to " + to); return true; }); } @Async public void notifyUser(String userId) { System.out.println("Notifying user: " + userId); } } // Unit test class EmailServiceAsyncTest { @Test void shouldReturnCompletedFutureWhenSendingEmail() throws Exception { EmailService service = new EmailService(); CompletableFuture<Boolean> result = service.sendEmailAsync("test@example.com", "Hello"); Boolean success = result.get(); // Wait for completion assertThat(success).isTrue(); } @Test void shouldCompleteWithinTimeout() { EmailService service = new EmailService(); CompletableFuture<Boolean> result = service.sendEmailAsync("test@example.com", "Hello"); assertThat(result).isCompletedWithValue(true); } } ``` ## Async Service with Mocked Dependencies ```java @Service public class UserNotificationService { private final EmailService emailService; private final SmsService smsService; public UserNotificationService(EmailService emailService, SmsService smsService) { this.emailService = emailService; this.smsService = smsService; } @Async public CompletableFuture<String> notifyUserAsync(String userId) { return CompletableFuture.supplyAsync(() -> { emailService.send(userId); smsService.send(userId); return "Notification sent"; }); } } @ExtendWith(MockitoExtension.class) class UserNotificationServiceAsyncTest { @Mock private EmailService emailService; @Mock private SmsService smsService; @InjectMocks private UserNotificationService notificationService; @Test void shouldNotifyUserAsynchronously() throws Exception { CompletableFuture<String> result = notificationService.notifyUserAsync("user123"); String message = result.get(); assertThat(message).isEqualTo("Notification sent"); verify(emailService).send("user123"); verify(smsService).send("user123"); } @Test void shouldHandleAsyncExceptionGracefully() { doThrow(new RuntimeException("Email service failed")).when(emailService).send(any()); CompletableFuture<String> result = notificationService.notifyUserAsync("user123"); assertThatThrownBy(result::get) .isInstanceOf(ExecutionException.class) .hasCauseInstanceOf(RuntimeException.class); } } ``` ## Testing `@Scheduled` Methods ```java @Component public class DataRefreshTask { private final DataRepository dataRepository; public DataRefreshTask(DataRepository dataRepository) { this.dataRepository = dataRepository; } @Scheduled(fixedDelay = 60000) public void refreshCache() { dataRepository.findAll(); // Update cache } @Scheduled(cron = "0 0 * * * *") // Every hour public void cleanupOldData() { dataRepository.deleteOldData(LocalDateTime.now().minusDays(30)); } } @ExtendWith(MockitoExtension.class) class DataRefreshTaskTest { @Mock pr