Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.
82
82%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Risky
Do not use without reviewing
This skill provides comprehensive patterns for testing Spring ApplicationEvent publishers and event listeners using JUnit 5. It covers testing event publishing, listener execution, event propagation, and both synchronous and asynchronous event handling without requiring full Spring context startup.
Use this skill when:
@Mock to mock the event publisherArgumentCaptor.forClass(EventType.class)<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.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>dependencies {
implementation("org.springframework.boot:spring-boot-starter")
testImplementation("org.junit.jupiter:junit-jupiter")
testImplementation("org.mockito:mockito-core")
testImplementation("org.assertj:assertj-core")
}// Custom application event
public class UserCreatedEvent extends ApplicationEvent {
private final User user;
public UserCreatedEvent(Object source, User user) {
super(source);
this.user = user;
}
public User getUser() {
return user;
}
}
// Service that publishes events
@Service
public class UserService {
private final ApplicationEventPublisher eventPublisher;
private final UserRepository userRepository;
public UserService(ApplicationEventPublisher eventPublisher, UserRepository userRepository) {
this.eventPublisher = eventPublisher;
this.userRepository = userRepository;
}
public User createUser(String name, String email) {
User user = new User(name, email);
User savedUser = userRepository.save(user);
eventPublisher.publishEvent(new UserCreatedEvent(this, savedUser));
return savedUser;
}
}
// Unit test
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class UserServiceEventTest {
@Mock
private ApplicationEventPublisher eventPublisher;
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void shouldPublishUserCreatedEvent() {
User newUser = new User(1L, "Alice", "alice@example.com");
when(userRepository.save(any(User.class))).thenReturn(newUser);
ArgumentCaptor<UserCreatedEvent> eventCaptor = ArgumentCaptor.forClass(UserCreatedEvent.class);
userService.createUser("Alice", "alice@example.com");
verify(eventPublisher).publishEvent(eventCaptor.capture());
UserCreatedEvent capturedEvent = eventCaptor.getValue();
assertThat(capturedEvent.getUser()).isEqualTo(newUser);
}
}// Event listener
@Component
public class UserEventListener {
private final EmailService emailService;
public UserEventListener(EmailService emailService) {
this.emailService = emailService;
}
@EventListener
public void onUserCreated(UserCreatedEvent event) {
User user = event.getUser();
emailService.sendWelcomeEmail(user.getEmail());
}
}
// Unit test for listener
class UserEventListenerTest {
@Test
void shouldSendWelcomeEmailWhenUserCreated() {
EmailService emailService = mock(EmailService.class);
UserEventListener listener = new UserEventListener(emailService);
User newUser = new User(1L, "Alice", "alice@example.com");
UserCreatedEvent event = new UserCreatedEvent(this, newUser);
listener.onUserCreated(event);
verify(emailService).sendWelcomeEmail("alice@example.com");
}
@Test
void shouldNotThrowExceptionWhenEmailServiceFails() {
EmailService emailService = mock(EmailService.class);
doThrow(new RuntimeException("Email service down"))
.when(emailService).sendWelcomeEmail(any());
UserEventListener listener = new UserEventListener(emailService);
User newUser = new User(1L, "Alice", "alice@example.com");
UserCreatedEvent event = new UserCreatedEvent(this, newUser);
// Should handle exception gracefully
assertThatCode(() -> listener.onUserCreated(event))
.doesNotThrowAnyException();
}
}class UserCreatedEvent extends ApplicationEvent {
private final User user;
private final List<String> notifications = new ArrayList<>();
public UserCreatedEvent(Object source, User user) {
super(source);
this.user = user;
}
public void addNotification(String notification) {
notifications.add(notification);
}
public List<String> getNotifications() {
return notifications;
}
}
class MultiListenerTest {
@Test
void shouldNotifyMultipleListenersSequentially() {
EmailService emailService = mock(EmailService.class);
NotificationService notificationService = mock(NotificationService.class);
AnalyticsService analyticsService = mock(AnalyticsService.class);
UserEventListener emailListener = new UserEventListener(emailService);
UserEventListener notificationListener = new UserEventListener(notificationService);
UserEventListener analyticsListener = new UserEventListener(analyticsService);
User user = new User(1L, "Alice", "alice@example.com");
UserCreatedEvent event = new UserCreatedEvent(this, user);
emailListener.onUserCreated(event);
notificationListener.onUserCreated(event);
analyticsListener.onUserCreated(event);
verify(emailService).send(any());
verify(notificationService).notify(any());
verify(analyticsService).track(any());
}
}@Component
public class ConditionalEventListener {
@EventListener(condition = "#event.user.age > 18")
public void onAdultUserCreated(UserCreatedEvent event) {
// Handle adult user
}
}
class ConditionalListenerTest {
@Test
void shouldProcessEventWhenConditionMatches() {
// Test logic for matching condition
}
@Test
void shouldSkipEventWhenConditionDoesNotMatch() {
// Test logic for non-matching condition
}
}@Component
public class AsyncEventListener {
private final SlowService slowService;
@EventListener
@Async
public void onUserCreatedAsync(UserCreatedEvent event) {
slowService.processUser(event.getUser());
}
}
class AsyncEventListenerTest {
@Test
void shouldProcessEventAsynchronously() throws Exception {
SlowService slowService = mock(SlowService.class);
AsyncEventListener listener = new AsyncEventListener(slowService);
User user = new User(1L, "Alice", "alice@example.com");
UserCreatedEvent event = new UserCreatedEvent(this, user);
listener.onUserCreatedAsync(event);
// Event processed asynchronously
Thread.sleep(100); // Wait for async completion
verify(slowService).processUser(user);
}
}Event not being captured: Verify ArgumentCaptor type matches event class.
Listener not invoked: Ensure event is actually published and listener is registered.
Async listener timing issues: Use Thread.sleep() or Awaitility to wait for completion.
plugins
developer-kit-ai
skills
chunking-strategy
prompt-engineering
developer-kit-aws
skills
aws
aws-cli-beast
aws-cost-optimization
aws-drawio-architecture-diagrams
aws-sam-bootstrap
aws-cloudformation
aws-cloudformation-auto-scaling
references
aws-cloudformation-bedrock
references
aws-cloudformation-cloudfront
references
aws-cloudformation-cloudwatch
references
aws-cloudformation-dynamodb
references
aws-cloudformation-ec2
aws-cloudformation-ecs
references
aws-cloudformation-elasticache
aws-cloudformation-iam
references
aws-cloudformation-lambda
references
aws-cloudformation-rds
aws-cloudformation-s3
references
aws-cloudformation-security
references
aws-cloudformation-task-ecs-deploy-gh
aws-cloudformation-vpc
developer-kit-core
skills
developer-kit-java
skills
aws-lambda-java-integration
aws-rds-spring-boot-integration
aws-sdk-java-v2-bedrock
aws-sdk-java-v2-core
aws-sdk-java-v2-dynamodb
aws-sdk-java-v2-kms
aws-sdk-java-v2-lambda
aws-sdk-java-v2-messaging
aws-sdk-java-v2-rds
aws-sdk-java-v2-s3
aws-sdk-java-v2-secrets-manager
graalvm-native-image
langchain4j
langchain4j-mcp-server-patterns
langchain4j-ai-services-patterns
references
langchain4j-mcp-server-patterns
references
langchain4j-rag-implementation-patterns
references
langchain4j-spring-boot-integration
langchain4j-testing-strategies
langchain4j-tool-function-calling-patterns
langchain4j-vector-stores-configuration
references
qdrant
references
spring-ai-mcp-server-patterns
references
spring-boot-actuator
spring-boot-cache
spring-boot-crud-patterns
spring-boot-dependency-injection
spring-boot-event-driven-patterns
spring-boot-openapi-documentation
spring-boot-project-creator
spring-boot-resilience4j
spring-boot-rest-api-standards
spring-boot-saga-pattern
spring-boot-security-jwt
assets
references
scripts
spring-boot-test-patterns
spring-data-jpa
references
spring-data-neo4j
references
unit-test-application-events
unit-test-bean-validation
unit-test-boundary-conditions
unit-test-caching
unit-test-config-properties
unit-test-controller-layer
unit-test-exception-handler
unit-test-json-serialization
unit-test-mapper-converter
unit-test-parameterized
unit-test-scheduled-async
unit-test-service-layer
unit-test-utility-methods
unit-test-wiremock-rest-api
developer-kit-php
skills
aws-lambda-php-integration
developer-kit-python
skills
aws-lambda-python-integration
developer-kit-tools
developer-kit-typescript
skills
aws-lambda-typescript-integration
better-auth
drizzle-orm-patterns
dynamodb-toolbox-patterns
references
nestjs
nestjs-best-practices
nestjs-code-review
nestjs-drizzle-crud-generator
scripts
nextjs-app-router
nextjs-authentication
nextjs-code-review
nextjs-data-fetching
references
nextjs-deployment
nextjs-performance
nx-monorepo
react-code-review
react-patterns
references
shadcn-ui
tailwind-css-patterns
references
tailwind-design-system
references
turborepo-monorepo
typescript-docs
typescript-security-review
zod-validation-utilities