Share
Embed
WeDontNeedNoMockTrouble Devoxx
Adapter contract testing
How to test your integrations with external dependencies and reuse those same tests to build simulators.
The simulators allows you to test without any mocks in your whole codebase
martinsson
August 20, 2025
Transcript
76 slides
-
Mathieu Cans & Johan Martinsson Adapter contract testing En fi
nir avec les problèmes de mocks -
We don’t need no mock trouble Why do we shift
away from using mock Photo de Jonathan Borba sur Unsplash -
The mock addiction Where does it come from? SUT A
B Test D C SUT A B Test D C -
All tests pass but we have a bug in production
Where does it come from? -
But the tests are passing • A missed use case
• Many layers of tests, with a bad mock somewhere • Surprise behavious of a dependency Bugs in prod Photo de Xavi Cabrera sur Unsplash -
False assumptions Mock problems Assumption: 4G | 5G Real world:
- 5G - 4G - 4G - 4G - 4g 💥 -
Tech language - Not business facing Confusing intent Verbose Mock
problems Test SUT Stub Spy Setup Veri fi cation Test SUT Simulator Other classes Setup Veri fi cation -
Domain The hexagonal opportunity Domain and infrastructure segregation Domain Infrastructure
Infrastructure code ⛔ ✅ -
Domain The hexagonal opportunity Dependency inversion Domain Adapters Infrastructure Ports
Infrastructure code ⛔ Adapters ✅ -
Domain The hexagonal opportunity Plugin behavior Domain Adapters Adapters Adapters
Infrastructure Ports Infrastructure code Other adapter ✅ -
Domain Simulators 🤖 Simulators 🤖 Infrastructure Ports Test The hexagonal
opportunity Use simulators to test your domain with con fi dence Adapters Adapters -
Adapter contract test Test the real adapter de fi ne
the contract Adapters Infrastructure Test Including anti-corruption layer ✍ -
Use the contract to create strong simulators Adapters Infrastructure Test
Including anti-corruption layer Simulator Contract = running the same test Adapter contract test ✍ 💪 -
• Establish a contract with simulator against a DB •
Establish a contract with a read- only dependency • Use simulators to test the domain with con fi dence Road-book high level view Photo de Jesse Bowser sur Unsplash -
Make groups of 2 ou 3 💡 Tips for pair/mob
• Driver role : Have the keyboard Responsible to translate ideas to code • Navigators role : Tells the driver what you want to be done • Switch roles often • If you have an idea : be a kind navigator Hands-on setup Photo de Halogen Condense sur Unsplash -
Hands-on setup Setup steps 1. Open the project fi le
of your chosen language 2. Follow README instruction : 1. Start mongo db locally docker run --rm -p 27017:27017 --name mongo_contract_testing -d mongo 2. Start race server locally docker run --rm -d -p8000:8000 --name snail-race-server mathieucans/snail-race-server:latest 3. Execute requirement test If you are done : help others! 🤝 -
Establish a contract with simulator against a DB • Write
a test against a database • Extract the contract test • Use contract test to write a simulator Road-book Step 1 Photo de Glenn Carstens-Peters sur Unsplash -
Exercice 1 - Contract test a database Test the real
adapter de fi ne the contract BetRepositoryMongoDb BetRepository MongoDbTest Mongo DB BetRepository -
Contract test a database 💡 Tips : • Don’t panic
with mongo syntax. • Refers to MongoDbCheatSheet.md if needed Exercice 1 -
Use Contract test to implement simulator BetRepositoryMongoDb BetRepository MongoDb Test
Mongo DB BetRepository BetRepositorySimulator BetRepository Simulator Test BetRepository Contract -
Use Contract test to implement simulator JAVA WAY BetRepositoryMongoDb BetRepository
MongoDb Test Mongo DB BetRepository BetRepositorySimulator BetRepository Simulator Test BetRepository Contract Inherit Inherit Setup only Setup only All tests are here ➡ -
Contract test BetRepositoryMongoDb Conclusions • Did you test the boundaries?
• Gotcha: in-memory does not copy objects -
Solved problems No more technical tests Test SUT Stub Spy
Setup Veri fi cation SOLVED -
Demo - Establish contract with read-only dep. Contract test a
read only provider RaceResultProviderHttp RaceResultProvider Http Test RaceResultProvider SnailRaceServer -
Read-only api 1. Make a contract with the dependency 1.
Explore the endpoint with a unit test 2. Use the json response to create infrastructure types 3. Write a contract test that uses the desired port 4. Unit test the mapping (infra -> domain) with pure unit tests 2. Write simulator Roadbook Step 2 -
Orange Restricted Anti corruption layer Domain side RaceResultProvider (Port) snail-
race-server Infrastructure side SnailRaces SnailRace Podium Snail * 1 3 -
Use Contract test to implement simulator RaceResultProviderHttp RaceResultProvider HttpTest RaceResultProvider
RaceResultSimulatorSimulator RaceResultProvider SimulatorTest RaceResultProvider Contract Simulation SnailRaceServer -
Anti-Corruption Layer On steroids 1. Perform utterly daring validations and
restructurings on the data from providers 👉 Allowing to build highly typed domain objects 2. Use the tests to run them on massive amounts of data 3. You’ve simpli fi ed the job for the domain and you can be certain the simpli fi cation is valid Tranformation Validation Normalisation Dirty DTO Clean Domain Object -
• ✅ External api changes • ✅ Refactorability of the
adapter • ✅ No more technical tests Solved problems Photo de Bozhin Karaivanov sur Unsplash -
Real world: - 5G - 4G - 4G - 4G
- 4g 💥 Solved problems False assumptions SOLVED Assumption: - 4G - 5G -
Exercice - Test application with confidence Use simulator to test
your domain with con fi dence Domain RaceResultProviderSimulator BetRepositorySimulator Ports BetApplication Test -
Use simulators to test the domain with con fi dence
• Use the simulators • Write a f….g test 😂 • Take time to appreciate: • domain language in tests • test brievety • fast feedback • con fi ence because we’re utterly close to the production behaviour and interaction Roadbook Step3 -
Domain rules The application can register bets • registering a
bet is done by providing • gambler name • the 3 numbers of snails on the podium The application lists the winners according to last race ran. To win a bet : • The podium match exactly the race result • The bet has been registered at least 3 seconds before the race timestamp • A bet is valid only for the next race -
Exercice Use simulator to test your domain • ➡ Checkout
branch start-step3 • Start writing tests -
• ✅ External api changes • ✅ Refactorability of the
adapter • ✅ No more technical tests • ✅ Complexity isolation • ✅ False assumptions … Solved problems Photo de Bozhin Karaivanov sur Unsplash -
Solved problems No more technical tests Test SUT Stub Spy
Setup Veri fi cation SOLVED -
Solved problems Lightning ⚡ fast 🚀 tests BONUS Photo de
Bill Jelen sur Unsplash -
Contract tests in the CI • Put in a separate
pipeline (possibly di ff erent triggers/periodicity) • Put in an optional pipeline/step • Use as uptime-bot • No CI ! - the main use is on dev machine -
Con fi ance dans les tests du domaine Tests de
l’infra pertinents Migration de dépendance facile Refactorabilité ++ Isolation de la complexité Abstraction forte The 5 bene fi ts -
References • Contract Test - Martin Fowler • Testing Without
Mocks - James Shore • Architecture Hexagonale : gestion de la complexité logicielle et de la dette technique - Julien Topçu • Outside-In Diamond TDD - Thomas Pierrain -
Orange Restricted Use contract test for production metrics • Use
exactly same test to generate metrics on production • Useful when traffic still small • Better diagnostic • OPS can monitor them -
Example: gmail reply detection Gmail has no native way to
check if an email has been replied to It can be implemented through threads Need to expose this to the domain 1. Discovered how thread works through contract tests 2. Use these tests to write a simulator like gmail 3. Very productive and con fi dent in implementing the domain logic -
Example : api change Both simulators and contract test shave
been written to consume orange mails The application was tested with simulators Need to change end point used to read mails in the adapter (QOS issue) 1. Write the adapter with the new end point 2. Check the behavior still works as the old one and the simulator 3. Integrate the new end point safely without change neither domain code nor domain tests -
Example: remote fi le system (OneDrive) • Very slow, in
particular for listing nested folders • There were around 15 methods on it • Having the fake made it very easy to implement a good caching system • As a result it was easy to implement both a persistent and an ephemeral caching system Storage OneDrive Slow -
Example: public company registry • Getting info about companies •
Problem: not really. Read-only but stable • Solution: keep the exact assertions • In retrospect: They changed sometimes, but not often. Our app Data.gouv -
Example: data.entreprise.gouv • Getting (more) info about companies • Problem:
Heteregenous data • Solution: Try ingesting big amounts of data as a test • Result: We discovered rare problems in dev as opposed to production Our app Data.gouv Heteregenous data -
Example: Android system • A js-app running on android, it
has a chatty api with a native app. • Problem: complex and wrong mocking • Solution: build a simulator (without contract testing) • Gain: Reliable tests of the isolated js-app js app native app Complex interactions -
Example: Run tests on DB production • Warning : after
the training • Running contract test in isolation as much as possible