Spring Cloud Contract and two services that are both producers and consumers

TL;DR: how to generate stubs for two services that exchange information (therefore both are producers and consumers)?

Hi,

I’m developing an app using microservices architecture with maven, Spring Boot, Spring Cloud Stream, with Spring Cloud Contract Verifier and Stub Runner for integration tests. I’m using event sourcing to publish events through Kafka. So I have something like this:

my-app
|-- pom.xml (sets up both subprojects as children)
|-- person-service (handles person's money)
|  |-- src/main/java/person/EventProducer.java (produces a personCreated event)
|  `-- src/main/java/person/EventConsumer.java (consumes an objectBought event)
`-- object-service (handles objects that can be bought)
   |-- src/main/java/object/EventProducer.java (produces an objectBought event)
   `-- src/main/java/object/EventConsumer.java (consumes a personCreated event)

Now, my problem is that with Event Sourcing, both services are producers and consumers. So I have both services generating stubs for the other service to consume, like this:

person-service integration tests

@SpringBootTest(classes = PersonApplication.class, webEnvironment = RANDOM_PORT)
@AutoConfigureStubRunner(ids = "example.com:object-service", stubsMode = LOCAL)
class PersonIntegrationTests extends Specification {
    @Inject StubTrigger stubTrigger
    // tests
}

object-service integration tests

@SpringBootTest(classes = ObjectApplication.class, webEnvironment = RANDOM_PORT)
@AutoConfigureStubRunner(ids = "com.example:person-service", stubsMode = LOCAL)
class ObjectIntegrationTests extends Specification {
    @Inject StubTrigger stubTrigger
    // tests
}

Now, of course, running mvn clean install in the parent project gives me an error because regardless of the build order, the stubs in the other project have not yet been generated.

I’ve looked at the Spring Cloud Contract Verifier documentation and its samples, but I haven’t found a solution for this scenario.

Right now as a workaround I run first mvn clean install -DskipTests to generate the stubs first, then mvn clean install to run all tests. I’ve also tried setting up an external contracts project that both services could use, but each service still generates its own stubs. I think changing stubsMode to CLASSPATH wouldn’t help either, as the stubs would still need to be created in the first place…

I though of creating a “stub service” that would implement the producers of each service, so that each project would refer to it for the stubs (so I’d use ids = "com.example:stub-service" in each integration test). But that seems like a hassle and could lead to human error, as each change in contract and each additional service publishing in the Event Store would need to be reflected in the stub service.

My question is: is there a better way to generate the stubs for both projects before running my integration tests? I’d like to be able to be able to build and run integration tests using mvn clean install only.

Answer

That’s a very good question. It’s a chicken and egg like problem.

Right now as a workaround I run first mvn clean install -DskipTests to generate the stubs first, then mvn clean install to run all tests. I’ve also tried setting up an external contracts project that both services could use, but each service still generates its own stubs

This seems very reasonable. You could also put some of the tests in a different suite and first run the tests with one profile (e.g. producer) and then another one (e.g. consumer). But what you did seems the fastest.

You can file an issue in Spring Cloud Contract and we can try to investigate how to make the developer’s life easier in such cases.

Leave a Reply

Your email address will not be published. Required fields are marked *