Contract testing for Kafka event based services
Table of Contents
- Contract testing for Kafka event based services
- Table of Contents
- Key takeaway
- Why
- The bigger picture
- Effective communication requirements
- Show me the code
- What's next?
Disclaimer |
---|
Opinionated content follows :-) |
Key takeaway
.. and target of this presentation is try to persuade you that:
Contracts tests are a promising and effective way to reduce end-to-end tests.
Why
.. reduce the number of end-to-end tests?
- Slow
- Brittle
- Expensive to set up and maintain
- We cannot do exhaustive testing
- Slow feedback
- No build time feedback
- Which team owns the end-to-end test?
- writing
- fixing
- maintaining
The bigger picture
Contract tests sit between end-to-end and component tests.

Effective communication requirements
Focusing on ServiceB1
and ServiceA1
services.
- ServiceA1 can de-serialise the event/ bytes, serialised by ServiceB1
- The de-serialised event contains all necessary data for ServiceA1 to perform its business logic (has the proper semantics)
- (1) and (2) though related, are not the same!
- A consumer able to de-serialise, does not mean it can deliver its business purpose
- Avro required fields capture what is required from an event modelling perspective, not the consumer
- One contract
per consumer
orper consumer, per consumer use case
would be better?- Different consumers may require different fields
- Different consumers may require different values of the same Enum field
- Doing compatible avro schema changes usually leads to reducing avro required fields

Consumer can read producer data
The avro schemas used by the ServiceA1 Consumer
and ServiceB1 Producer
are compatible, so that ServiceA1
can de-serialise the bytes, serialised by ServiceB1
.
Consumer can deliver business value
The de-serialised event contains all necessary data for ServiceA1
to perform its business logic (has the proper semantics).
This can be achieved in two ways:
Components tests
Contract tests
Component tests
Currently, we do a lot of them.
Consumer

Pros:
- Exist on the ServiceA1 (consumer) bitbucket repo
- Run as part of the build process
- Fast
- Stable
- Isolated
- Easy to set up
Cons:
- Test mocks the actual producer
- Stall mocks issues!
- ServiceB1 (i.e. actual runtime producer) moves to a new kafka-schemas version
- ServiceB1 service removes an avro optional field that is required from the ServiceA1 (i.e. consumer) perspective
Producer

Pros:
- Exist on the ServiceB1 (producer) bitbucket repo
- Run as part of the build process
- Fast
- Stable
- Isolated
- Easy to set up
Cons:
- How does the producer know that it emits events that are actually what the consumer expects? I does not.
- ServiceA1 requires a particular value of an enum field (e.g.
status
to beFULFILLED
), but the producer never generates aFULFILLED
event?
- ServiceA1 requires a particular value of an enum field (e.g.
Contract tests to the rescue
Consumer

Pros:
- Exist on the ServiceB1 (producer) bitbucket repo
- Run as part of the build process
- Fast
- Stable
- Isolated
- Easy to set up
and an extra one:
- No stall mocks issue!
Producer

Pros:
- Exist on the ServiceB1 (producer) bitbucket repo
- Run as part of the build process
- Fast
- Stable
- Isolated
- Easy to set up
2 extras:
- If producer by mistake stops following the contract producer build fails!
- Meaning, the producer emits events that the consumers actually expect
Triggering the producer
In our use case we have ServiceB1 querying the ServiceB2 DB emitting appropriate data as avro events to the downstream consumers.
How can we trigger the producer to emit the proper event, so that we verify it against its contract?
Generate ServiceB1 Producer input data as part of the contract test

Do we have a guarantee:
- that the input data (
c1
ando1
) used are actually provided during runtime? - or even that the
DB schema
is correct?
No! We have to add an extra contract test!

Show me the code
Open Intellij..
What's next?
- Should the producer have a contract per consumer's use case scenario?
- The consuming service uses the sample event as is for testing these use cases
- Maybe contract tests should focus on verifying just event structure
- Is there any benefit of using avro, regarding schema evolution, if you do contract testing?
- What about non JVM producers/ consumer?
- What about non Java producers?
- UI is a Nodejs REST consumer