Microservices Patterns
Testing Microservices VII
Integration Testing Publish/Subscribe-Style
Interactions
Integration testing publish/subscribe-style interactions
● Services often publish domain events that are consumed by one or more other
services.
● Integration testing must verify that the publisher and its consumers agree on the
message channel and the structure of the domain events.
● Order Service, for example, publishes Order* events whenever it creates or updates an
Order aggregate.
● OrderHistory Service is one of the consumers of those events. We must, therefore,
write tests that verify that these services can interact.
Integration testing publish/subscribe-style interactions
● The following figure shows the approach to integration testing publish/subscribe
interactions.
● It’s quite similar to the approach used for testing REST interactions.
● As before, the interactions are defined by a set of contracts.
● What’s different is that each contract specifies a domain event.
Integration testing publish/subscribe-style interactions
Integration testing publish/subscribe-style interactions
● Each consumer-side test publishes the event specified by the contract and verifies
that OrderHistoryEventHandlers invokes its mocked dependencies correctly.
● Each consumer-side test publishes the event specified by the contract and verifies
that OrderHistoryEventHandlers invokes its mocked dependencies correctly.
Integration testing publish/subscribe-style interactions
● On the provider side, Spring Cloud Contract code-generates test classes that extend
MessagingBase, which is a hand-written abstract superclass.
● Each test method invokes a hook method defined by MessagingBase, which is
expected to trigger the publication of an event by the service.
● In this example, each hook method invokes OrderDomainEventPublisher, which is
responsible for publishing Order aggregate events.
● The test method then verifies that OrderDomainEventPublisher published the expected
event.
The Contract For Publishing An Ordercreated Event
[Link] {
label 'orderCreatedEvent'
input {
triggeredBy ('orderCreated()')
}
outputMessage {
sentTo('[Link]')
body('''{"orderDetails":{"lineItems":[{"quantity":5,"menuItemId":"1",
"name":"Chicken Vindaloo","price":"12.34","total":"61.70"}],
"orderTotal":"61.70","restaurantId":1,
"consumerId":1511300065921},"orderState":"APPROVAL_PENDING"}''')
headers {
header('event-aggregate-type',
'[Link]')
header('event-aggregate-id', '1')
}
}}
The Contract For Publishing An OrderCreated Event
The contract also has two other important elements:
● Label—is used by a consumer test to trigger publication of the event by Spring Contact
● TriggeredBy—the name of the superclass method invoked by the generated test
method to trigger the publishing of the event
Consumer-Driven Contract Tests For Order Service
● The provider-side test for Order Service is another consumer-driven contract
integration test.
● It verifies that OrderDomainEventPublisher, which is responsible for publishing Order
aggregate domain events, publishes events that match its clients’ expectations.
● The following listing shows MessagingBase, which is the base class for the test
classes code-generated by Spring Cloud Contract.
● It’s responsible for configuring the OrderDomainEventPublisher class to use
in-memory messaging stubs.
● It also defines the methods, such as orderCreated(), which are invoked by the
generated tests to trigger the publishing of the event.
Consumer-Driven Contract Tests For Order Service
@RunWith([Link])
@SpringBootTest(classes = [Link],
webEnvironment = [Link])
@AutoConfigureMessageVerifier
public abstract class MessagingBase {
@Configuration
@EnableAutoConfiguration
@Import({[Link],
[Link],
[Link]})
public static class TestConfiguration {
@Bean
public OrderDomainEventPublisher
OrderDomainEventPublisher(DomainEventPublisher eventPublisher) {
return new OrderDomainEventPublisher(eventPublisher);
}
}
Consumer-Driven Contract Tests For Order Service
@Autowired
private OrderDomainEventPublisher OrderDomainEventPublisher;
protected void orderCreated() {
[Link](CHICKEN_VINDALOO_ORDER,
singletonList(new OrderCreatedEvent(CHICKEN_VINDALOO_ORDER_DETAILS)));
}
}
Consumer-Driven Contract Tests For Order Service
● This test class configures OrderDomainEventPublisher with in-memory messaging
stubs.
● orderCreated() is invoked by the test method generated from the contract shown
earlier. It invokes OrderDomainEventPublisher to publish an OrderCreated event.
● The test method attempts to receive this event and then verifies that it matches the
event specified in the contract. Let’s now look at the corresponding consumer-side
tests.
Consumer-Side Contract Test For The Order History
Service
● Order History Service consumes events published by Order Service. the adapter class
that handles these events is the OrderHistoryEventHandlers class.
● Its event handlers invoke OrderHistoryDao to update the CQRS view.
● The following listing shows the consumer-side integration test. It creates an
OrderHistoryEventHandlers injected with a mock OrderHistoryDao.
● Each test method first invokes Spring Cloud to publish the event defined in the
contract and then verifies that OrderHistoryEventHandlers invokes OrderHistoryDao
correctly.
The consumer-side integration test for the
OrderHistoryEventHandlers class
@RunWith([Link])
@SpringBootTest(classes= [Link],
webEnvironment= [Link])
@AutoConfigureStubRunner(ids =
{"[Link]:ftgo-order-service-contracts"}, workOffline = false)
@DirtiesContext
public class OrderHistoryEventHandlersTest {
@Configuration
@EnableAutoConfiguration
@Import({OrderHistoryServiceMessagingConfiguration .class,
TramCommandProducerConfiguration .class,
TramInMemoryConfiguration .class,
EventuateContractVerifierConfiguration .class})
public static class TestConfiguration {
The consumer-side integration test for the
OrderHistoryEventHandlers class
@Bean
public OrderHistoryDao orderHistoryDao() {
return mock([Link]);
}}
@Test
public void shouldHandleOrderCreatedEvent() throws ... {
stubFinder. trigger("orderCreatedEvent");
eventually (() -> {
verify(orderHistoryDao)
.addOrder(any([Link]), any([Link]));
});
}
}
The consumer-side integration test
● The shouldHandleOrderCreatedEvent() test method tells Spring Cloud Contract to
publish the OrderCreated event.
● It then verifies that OrderHistoryEventHandlers invoked [Link]().
● Testing both the domain event’s publisher and consumer using the same contracts
ensures that they agree on the API.
The Next Post
Integration contract tests for
asynchronous request/response
interactions