Merge pull request #16204 from etrandafir93/features/BAEL-7547-testing_spring_events
BAEL-7547: testing spring events article
This commit is contained in:
commit
20ee012f25
|
@ -17,7 +17,6 @@
|
|||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.kafka</groupId>
|
||||
<artifactId>spring-kafka</artifactId>
|
||||
|
@ -28,20 +27,27 @@
|
|||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.modulith</groupId>
|
||||
<artifactId>spring-modulith-events-api</artifactId>
|
||||
<version>${spring-modulith-events-kafka.version}</version>
|
||||
<version>${spring-modulith.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.modulith</groupId>
|
||||
<artifactId>spring-modulith-events-kafka</artifactId>
|
||||
<version>${spring-modulith-events-kafka.version}</version>
|
||||
<version>${spring-modulith.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.modulith</groupId>
|
||||
<artifactId>spring-modulith-starter-jpa</artifactId>
|
||||
<version>${spring-modulith-events-kafka.version}</version>
|
||||
<version>${spring-modulith.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.modulith</groupId>
|
||||
<artifactId>spring-modulith-starter-test</artifactId>
|
||||
<version>${spring-modulith.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -54,7 +60,6 @@
|
|||
<artifactId>spring-boot-testcontainers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>kafka</artifactId>
|
||||
|
@ -73,7 +78,6 @@
|
|||
<version>${testcontainers.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
|
@ -87,16 +91,23 @@
|
|||
<version>${awaitility.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>${h2.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<spring-boot.version>3.1.5</spring-boot.version>
|
||||
<spring-modulith-events-kafka.version>1.1.2</spring-modulith-events-kafka.version>
|
||||
<spring-modulith.version>1.1.3</spring-modulith.version>
|
||||
<testcontainers.version>1.19.3</testcontainers.version>
|
||||
<awaitility.version>4.2.0</awaitility.version>
|
||||
<postgresql.version>42.3.1</postgresql.version>
|
||||
<h2.version>2.2.224</h2.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.springmodulith.application.events.orders;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
record Order(String id, String customerId, List<String> productIds, Instant timestamp) {
|
||||
|
||||
public Order(String customerId, List<String> productIds) {
|
||||
this(null, customerId, productIds, Instant.now());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package com.baeldung.springmodulith.application.events.orders;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public record OrderCompletedEvent(String orderId, String customerId, Instant timestamp) {
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.springmodulith.application.events.orders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
class OrderRepository {
|
||||
private final List<Order> orders = new ArrayList<>();
|
||||
|
||||
public Order save(Order order) {
|
||||
order = new Order(UUID.randomUUID()
|
||||
.toString(), order.customerId(), order.productIds(), order.timestamp());
|
||||
orders.add(order);
|
||||
return order;
|
||||
}
|
||||
|
||||
public List<Order> ordersByCustomer(String customerId) {
|
||||
return orders.stream()
|
||||
.filter(it -> it.customerId()
|
||||
.equals(customerId))
|
||||
.toList();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.springmodulith.application.events.orders;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class OrderService {
|
||||
|
||||
private final OrderRepository repository;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
public OrderService(OrderRepository orders, ApplicationEventPublisher eventsPublisher) {
|
||||
this.repository = orders;
|
||||
this.eventPublisher = eventsPublisher;
|
||||
}
|
||||
|
||||
public void placeOrder(String customerId, String... productIds) {
|
||||
Order order = new Order(customerId, Arrays.asList(productIds));
|
||||
// business logic to validate and place the order
|
||||
|
||||
Order savedOrder = repository.save(order);
|
||||
|
||||
OrderCompletedEvent event = new OrderCompletedEvent(savedOrder.id(), savedOrder.customerId(), savedOrder.timestamp());
|
||||
eventPublisher.publishEvent(event);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.baeldung.springmodulith.application.events.rewards;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class LoyalCustomersRepository {
|
||||
|
||||
private List<LoyalCustomer> customers = new ArrayList<>();
|
||||
|
||||
public Optional<LoyalCustomer> find(String customerId) {
|
||||
return customers.stream()
|
||||
.filter(it -> it.customerId()
|
||||
.equals(customerId))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public void awardPoints(String customerId, int points) {
|
||||
var customer = find(customerId).orElseGet(() -> save(new LoyalCustomer(customerId, 0)));
|
||||
|
||||
customers.remove(customer);
|
||||
customers.add(customer.addPoints(points));
|
||||
}
|
||||
|
||||
public LoyalCustomer save(LoyalCustomer customer) {
|
||||
customers.add(customer);
|
||||
return customer;
|
||||
}
|
||||
|
||||
public boolean isLoyalCustomer(String customerId) {
|
||||
return find(customerId).isPresent();
|
||||
}
|
||||
|
||||
public record LoyalCustomer(String customerId, int points) {
|
||||
|
||||
LoyalCustomer addPoints(int points) {
|
||||
return new LoyalCustomer(customerId, this.points() + points);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.springmodulith.application.events.rewards;
|
||||
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baeldung.springmodulith.application.events.orders.OrderCompletedEvent;
|
||||
|
||||
@Service
|
||||
public class LoyaltyPointsService {
|
||||
|
||||
public static final int ORDER_COMPLETED_POINTS = 60;
|
||||
private final LoyalCustomersRepository loyalCustomers;
|
||||
|
||||
public LoyaltyPointsService(LoyalCustomersRepository loyalCustomers) {
|
||||
this.loyalCustomers = loyalCustomers;
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void onOrderCompleted(OrderCompletedEvent event) {
|
||||
// business logic to award points to loyal customers
|
||||
loyalCustomers.awardPoints(event.customerId(), ORDER_COMPLETED_POINTS);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.baeldung.springmodulith.application.events;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
import com.baeldung.springmodulith.application.events.orders.OrderCompletedEvent;
|
||||
import com.baeldung.springmodulith.application.events.rewards.LoyalCustomersRepository;
|
||||
|
||||
@SpringBootTest
|
||||
class EventListenerUnitTest {
|
||||
|
||||
@Autowired
|
||||
private LoyalCustomersRepository customers;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher testEventPublisher;
|
||||
|
||||
@Test
|
||||
void whenPublishingOrderCompletedEvent_thenRewardCustomerWithLoyaltyPoints() {
|
||||
OrderCompletedEvent event = new OrderCompletedEvent("order-1", "customer-1", Instant.now());
|
||||
|
||||
testEventPublisher.publishEvent(event);
|
||||
|
||||
assertThat(customers.find("customer-1"))
|
||||
.isPresent().get()
|
||||
.hasFieldOrPropertyWithValue("customerId", "customer-1")
|
||||
.hasFieldOrPropertyWithValue("points", 60);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.baeldung.springmodulith.application.events;
|
||||
|
||||
import com.baeldung.springmodulith.application.events.orders.OrderService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest
|
||||
class EventPublisherUnitTest {
|
||||
|
||||
@Autowired
|
||||
OrderService orderService;
|
||||
|
||||
@Autowired
|
||||
TestEventListener testEventListener;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
testEventListener.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenPlacingOrder_thenPublishApplicationEvent() {
|
||||
orderService.placeOrder("customer1", "product1", "product2");
|
||||
|
||||
assertThat(testEventListener.getEvents())
|
||||
.hasSize(1).first()
|
||||
.hasFieldOrPropertyWithValue("customerId", "customer1")
|
||||
.hasFieldOrProperty("orderId")
|
||||
.hasFieldOrProperty("timestamp");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.baeldung.springmodulith.application.events;
|
||||
|
||||
import com.baeldung.springmodulith.application.events.orders.OrderCompletedEvent;
|
||||
import com.baeldung.springmodulith.application.events.orders.OrderService;
|
||||
import com.baeldung.springmodulith.application.events.rewards.LoyalCustomersRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.modulith.test.ApplicationModuleTest;
|
||||
import org.springframework.modulith.test.ApplicationModuleTest.BootstrapMode;
|
||||
import org.springframework.modulith.test.Scenario;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import static java.time.Duration.ofMillis;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ApplicationModuleTest
|
||||
class SpringModulithScenarioApiUnitTest {
|
||||
|
||||
@Autowired
|
||||
OrderService orderService;
|
||||
|
||||
@Autowired
|
||||
LoyalCustomersRepository loyalCustomers;
|
||||
|
||||
@Test
|
||||
void whenPlacingOrder_thenPublishOrderCompletedEvent(Scenario scenario) {
|
||||
scenario.stimulate(() -> orderService.placeOrder("customer-1", "product-1", "product-2"))
|
||||
.andWaitForEventOfType(OrderCompletedEvent.class)
|
||||
.toArriveAndVerify(evt -> assertThat(evt)
|
||||
.hasFieldOrPropertyWithValue("customerId", "customer-1")
|
||||
.hasFieldOrProperty("orderId")
|
||||
.hasFieldOrProperty("timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReceivingPublishOrderCompletedEvent_thenRewardCustomerWithLoyaltyPoints(Scenario scenario) {
|
||||
scenario.publish(new OrderCompletedEvent("order-1", "customer-1", Instant.now()))
|
||||
.andWaitForStateChange(() -> loyalCustomers.find("customer-1"))
|
||||
.andVerify(it -> assertThat(it)
|
||||
.isPresent().get()
|
||||
.hasFieldOrPropertyWithValue("customerId", "customer-1")
|
||||
.hasFieldOrPropertyWithValue("points", 60));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.springmodulith.application.events;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.baeldung.springmodulith.application.events.orders.OrderCompletedEvent;
|
||||
|
||||
@Component
|
||||
class TestEventListener {
|
||||
|
||||
private final List<OrderCompletedEvent> events = new ArrayList<>();
|
||||
|
||||
@EventListener
|
||||
void onEvent(OrderCompletedEvent event) {
|
||||
events.add(event);
|
||||
}
|
||||
|
||||
public List<OrderCompletedEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
events.clear();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue