Werken bij, Trendsz, Test engineering, Testautomatisering, Tooling

Provider-driven en consumer-driven zijn twee verschillende benaderingen binnen contract-based testen. In deel 3 en deel 4 van mijn blogreeks heb ik beide benaderingen, afzonderlijk van elkaar, uitgebreid toegelicht. In dit blogartikel vergelijk ik de benaderingen met elkaar. Om er op die manier achter te komen of er een beste aanpak bestaat voor contract-based testen.

Contracten

In de vorige delen heb ik het al gehad over de inhoud van de contracten. De aanpakken verschillen en daardoor verschillen de contracten ook.

Provider-driven

Een provider-driven contract wordt geschreven door de provider. Hierin staan de definities en de documentatie van de interface. Het beschrijft alle technische details zoals: endpoints, de structuur van de response body, enz. Hierdoor voelt een provider-driven contract aan als technische documentatie. Het specificeert zoveel mogelijk details om zo min mogelijk ruimte te laten voor aannames.

Consumer-driven

Elke consumer schrijft een consumer-driven contract. Elk contract bevat request-response paren voor de interface. Deze paren zijn voorbeelden die laten zien hoe de interface zich moet gedragen. Een consumer-driven contract bevat alle eisen die een consumer aan een interface stelt met zo min mogelijk details. Door details weg te laten, weet de provider welke delen van hun interface daadwerkelijk gebruikt worden door de auteur van het contract.

Contract-based testen afb 3

Coupling

In deel 2 van mijn blogreeks heb ik het gehad over waarom coupling tijdens het testen belangrijk is. Coupling tijdens testen kan aan het einde van een lange werkdag het verschil zijn tussen hoofpijn en voldoening. Dat is maar een klein beetje overdreven. Helaas kunnen niet helemaal zonder coupling testen. We moeten een balans vinden in hoe zwaar we couplen tijdens het testen.

Contact-based testen is top, omdat het ons in staat stelt om te testen met weinig coupling. De mate van coupling is verschillend voor de benadering, hieronder leg ik uit wat de verschillen zijn.

Provider-driven

De provider-driven aanpak is de aanpak met minder coupling. Bij deze benadering is de provider helemaal niet afhankelijk van de consumers. De consumers zijn maar voor één ding afhankelijk van de provider, namelijk de correcte definities en documentatie van de interface.

Er is maar één ding dat de partijen coupled tijdens het testen. Hiermee is er voldoende coupling om stub-drift te voorkomen, maar niet voldoende voor bijvoorbeeld feedback over het gebruik van de interface.

 

Contract-based testen afb 4

Consumer-driven

De consumer-driven aanpak is de aanpak met meer coupling. De provider is hier afhankelijk van de consumers om correcte en realistische tests te sturen. Deze tests zijn tegelijkertijd de interface specificatie. De consumer is afhankelijk van de provider om zijn tests uit te voeren.

Twee zaken couplen de partijen tijdens het testen. De testen en het uitvoeren daarvan. Er is voldoende coupling voor feedback over het gebruik van de interface, maar niet genoeg voor bijvoorbeeld end-to-end tests.

Contract-based testen afb 5
Contract-based testen afb 6

Test types

We testen om de kwaliteit van de applicatie te waarborgen op meerdere aspecten. Hiervoor gebruiken we verschillende soorten tests. Enkele voorbeelden van testtypes zijn; technische correctheid, functionele correctheid, security en performance. Contract-based testen is een benadering om de correctheid te testen. We gebruiken het dan ook alleen om correctheid te testen en nooit voor het testen van andere aspecten.

Ik daag je uit om mijn laatste opmerking in twijfel te trekken. Het is een interessant gedachte-experiment. Kan het contract-based paradigm gebruikt worden met andere testtypes? Dit valt buiten de scope van dit blogartikel, dus laten we snel door gaan.

De provider-driven aanpak is zeer geschikt voor het testen van de technische correctheid van een applicatie. Echter, deze benadering is zeer ongeschikt wanneer je functionele correctheid over meerdere applicaties heen wilt testen. Bij de provider-driven aanpak vloeit er geen data van de ene applicatie naar de ander. Daardoor is het zinloos om functionele tests over de applicaties heen uit te voeren.

De consumer-driven aanpak is ook sterk in het waarborgen van de technische correctheid. Daarnast kun je de consumer-driven aanpak ook gebruiken voor het testen van een beetje functionele correctheid tussen applicaties. Bij deze benadering vloeit er namelijk wel data tussen applicaties. Let op, sommigen zien dit als een anti-patroon.

Contract-based testen afb 7

Development proces

Contract-based testen vraagt om twee dingen die gemaakt moeten worden bij iedere integratie. De integratie zelf en het bijbehorende contract. Als we beginnen met het schrijven van de contracten, noemen we dat contract-first. Als we beginnen met het bouwen van de integratie, noemen we dat implementation-first.

Contract-first

Bij contract-based testen is het altijd beter om contract-first te werken. Hierdoor kunnen we de contracten gebruiken als specificatie documenten tijdens het development process. We kunnen vervolgens dezelfde contracten gebruiken tijdens het testen. Dit geld voor beide benaderingen

In de provider-driven aanpak voel je de meeste voordelen van contract-first werken tijdens de interface implementatie aan de provider kant. Het contract is een specificatiedocument dat geschreven is met zo min mogelijk ruimte voor aannames. Dit maakt het contract erg nuttig voor alle betrokkenen tijdens development en testen. De provider kan het contract zelfs delen met hun consumers voordat ze klaar zijn met de implementatie van de interface.

De consumer-driven aanpak heeft meer voordelen wanneer we contract-first werken. In het contract specificeert de consumer hoe de interface moet werken. De provider implementeert de interface aan de hand van dit contract. Hierbij gebruikt de provider een TDD-achtige development cyclus. Het grootste verschil met TDD is dat de provider de testen niet zelf schrijft. De consumers doen dit voor hun. Dit alles resulteert in het volgende:

  1. De consumer heeft een beschikbaar dat exact doet wat ze nodig hebben. Gegarandeerd.
  2. Met minimale moeite heeft de provider heeft een interface gemaakt die precies genoeg functionaliteit biedt. Er is geen enkel stukje ongebruikte data. Er is geen enkel stukje ontbrekende data.
  3. De provider kan precies zien wie hun interface gebruikt, en op welke manier. Hiermee kan de provider op data gebaseerde beslissingen nemen over hun interface.
Contract-based testen afb 8

Implementation-first

Soms dwingt de situatie ons om implementation-first te werken. Bijvoorbeeld, wanneer we werken aan een bestaande interface. In deze situaties kunnen beide contract-based testing aanpakken alsnog gebruikt worden. U verliest echter de meeste procesvoordelen die komen met contract-based testen.

In deze situaties is het makkelijker om te beginnen met de provider-driven aanpak. In de meeste gevallen is er documentatie die makkelijk omgezet kan worden tot een provider-driven contract. De consumer-driven aanpak in een implementation-first situatie is vaak veel meer werk met weinig voordelen ten opzichte van de provider-driven aanpak.

Contract-based testen afb 9
Contract-based testen afb 10

Scaling

Één goed geteste interface is fijn, maar grote organisaties hebben honderden interfaces. Het is belangrijk om stil te staan bij hoe goed dingen werken op zo’n grote schaal. Bij het opschalen naar honderden interfaces moeten we:

  • Meer interfaces maken
    In beide benaderingen vereist het maken van een nieuwe interface het schrijven van contracten. Bij de provider-driven aanpak is het altijd één contract per interface. De consumer-driven aanpak vereist er een voor elke consument.
  • Meer testen schrijven
    Elke test kost werk. Maar in de provider-driven aanpak is het heel weinig werk. Om een test te upgraden naar een provider-driven contract-based test voeg je één assertion toe: De request en response komen overeen met het contract. We hebben veel profijt van zeer weinig moeite.
    Bij de consumer-driven aanpak voegt de consumer nieuwe testen toe aan hun contract. Daarna zorgt de provider ervoor dat alle contract tests slagen. Hiervoor moet de provider meestal testafhankelijkheden opzetten, zoals data, stubs, andere contracten, enz.
  • Meer consumers toevoegen
  • Wanneer onze interfaces populairder worden, krijgen we te maken met meer consumers. Bij de provider-driven aanpak hoeven we er alleen maar voor te zorgen dat nieuwe consumers het contract kunnen vinden.
    Bij de consumer-driven aanpak moet de provider voor elke nieuwe consumer een nieuwe testsuite implementeren. Deze nieuwe tests hebben meestal nieuwe testafhankelijkheden nodig. Deze afhankelijkheden opzetten kan veel werk zijn voor de provider.

Opschalen is een van de redenen dat coupling tijdens testen belangrijk is. De provider-driven aanpak heeft minder coupling, waardoor het beter schaalt.

Contract-based testen afb 11

Evolving the interface

Contract-based testen kan enorm helpen als een Service Evolution Pattern. Of, in andere woorden, het kan ons helpen wanneer we onze interfaces aanpassen. Regelmatig moeten we dingen in onze interfaces updaten, toevoegen of verwijderen. Wanneer we dat doen, willen we zeker weten dat we geen breaking change introduceren.

Met behulp van contracten kunnen we een hoop breaking changes in onze CI pipeline afvangen. Uiteindelijk komt dit er op neer dat de provider dingen die gebruikt worden door anderen niet te veel aanpast. Wat te veel is verschilt per communicatieprotocol. Bijvoorbeeld; een RESTful API is flexibeler dan een SOAP service is. Zorg ervoor dat je precies weet wat men een breaking change vindt voor jouw communicatieprotocol voordat je een interface aanpast.

Contract-based testen afb 12

Usage feedback

Bij het aanpassen van een interface is het nuttig om te weten hoe de interface gebruikt wordt door de consumers. Hoe specifieker, hoe beter. Het is tenslotte geen probleem om dingen kapot te maken waar niemand van afhankelijk is.

In de provider-driven aanpak kan de consumer niet met de provider praten tijdens het testen. Ze kunnen de provider niet vertellen hoe ze de interface gerbuiken. Hierdoor kan de provider niet bewijzen dat delen van de interface niet gebruikt worden. Hierdoor moeten ze er vanuit gaan dat er altijd iemand afhankelijk is van elk deel van de interface. Dit kan het erg vervelend maken om een interface aan te passen.

In de consumer-driven aanpak hebben we wel coupling van de consumers naar de provider. Doormiddel van deze coupling kunnen de consumers de provider precies vertellen hoe ze de interface gebruiken. De provider gebruikt de voorbeelden in het contract om er achter te komen hoe de interface gebruikt wordt. Ze gebruiken deze data om op data gebaseerde beslissingen nemen over hun interface.

Detecting breaking changes

Het kan moeilijk zijn om breaking changes te detecteren. Gelukkig kunnen contracten het een stuk makkelijker maken.

De meeste aanpassingen aan de interface gaan gepaard met een aanpassing in het contract. In de provider-driven aanpak kunnen de deze contract aanpassing gebruiken om de meeste breaking changes te detecteren. Elk voorbeeld dat gegenereerd wordt op basis van het oude contract moet succesvol gevalideerd kunnen worden met het nieuwe contract. Als de validatie faalt, hebben we een breaking change geintroduceerd. In dit geval moet de provider hun aanpassing terug draaien, of een nieuwe major versie van de interface introduceren.

In de consumer-driven aanpak is het simpel om breaking changes te detecteren. We draaien simpelweg onze contract tests. Een breaking change zorgt voor falende tests. Als een breaking change is gedecteerd moet de provider hun aanpassing terug draaien, of aan de consumer vragen of ze hun contract aan kunnen passen. Als beide geen optie is, kan de provider als laatste redmiddel een nieuwe marjor versie introduceren.

Contract-based testen afb 13

Conclusie

Wat is de beste aanpak? Helaas kan ik je geen antwoord geven op deze vraag. Simpelweg, omdat er in de wereld van software geen beste aanpak bestaat. Er is geen enkele aanpak die op iedere situatie van toepassing is. Dat is waarom ik nog steeds een baan heb als software tester.

Ik heb in dit blogartikel geprobeerd om de belangrijkste verschillen tussen de consumer-driven en provider-driven benadering toe te lichten. Hoewel er veel overlap is tussen beide benaderingen, hebben ze ieder hun sterke en zwakke punten. In mijn volgende blog wil ik kijken of en hoe beide benaderingen gecombineerd kunnen worden. Vullen ze elkaar aan? Of doen ze eerder afbreuk aan elkaar?

Contract-based testen afb 14
Podcast Bartosz ICT

Ben jij geïnteresseerd in contract-based testen?

Luister dan ook onze podcast waarin Sander van Beek en Stephan Dammers in gesprek gaan over dit onderwerp. Sander maakt jou wegwijs in de wereld van contract-based testen en vertelt uitgebreid over zijn ervaringen, wanneer contract-based testen wordt ingezet, de te verwachtte trends en nog veel meer. Je luistert de podcast via ons SoundCloud account.

    Wil je ons nieuwste Paarsz magazine per post ontvangen? Laat dan je gegevens achter.

    werkenbij overall

    Werken bij Bartosz?

    Vincent Verhelst

    Geïnteresseerd in Bartosz? Dan ga ik graag met jou in gesprek. We kunnen elkaar ontmoeten met een kop koffie bij ons op kantoor. Of tijdens ontbijt, lunch, borrel of diner op een plek die jou het beste uitkomt. Jij mag het zeggen.

    Mijn Paarsz