Pact: bi-directional contract testing


Introduction

The idea of bi-directional contract testing is a kind of contract testing which is neither consumer nor provider driven, rather each side, consumer and provider define their requirement (consumer side) resp. capabilities (provider side) and then the contract testing framework (e.g., pact) cross check the consumer requirements against provider capacities.

This allows a very lose coupling between consumer and provider development which makes the testing effort easier to manage and easier to scale.

pact bi-directional workshop

Here you can find a nice workshop by Pactflow to learn how pact bi-directinal contract testing works:

https://docs.pactflow.io/docs/workshops/bi-directional-contract-testing

I’ve been through that workshop and here are some of my notes where I was confused. Perhaps these notes could be helpful to someone else who had similar issues going through that workshop.

Here are my notes:

The change at step 1 in section “10. Breaking change detection\Provider breaking changes” is backward incompatible but its not breaking because no consumer is using the field ‘price’ ($Tag.Pact.Bi-Directional.Provider.FunctionalChange.BackwardIncompatible.NonBreaking)

So far so good. Then right after that we have the change at step 1 in section “10. Breaking change detection\Provider breaking changes” right after reverting the changes with “git checkout -–, which is backward incompatible and also breaking because there is a consumer which is using the field ‘name’ ($Tag.Pact.Bi-Directional.Provider.DesignChange.BackwardIncompatible.Breaking).

However, the test command npm t (which is the same as npm run test) passes and the incompatibility is only detected after the test results are published and during the can-i-deploy step.

So it seems that breaking changes to oas/product.yml can only be detected on Pactview with the can-i-deploy step.

However functional changes like the breaking change at step 1 in section “11. Conclusion\Next Steps?” ($Tag.Pact.Bi-Directional.Provider.FunctionalChange.BackwardIncompatible.Breaking) can be detected right away by the npm t command.

However, if we change the ‘name’ field instead of the ‘id’ field, the npm t command passes! The reason seems to be that the ‘name’ field, unlike the ‘id’ field, is not referred in the API descriptions in the oas/products.yml file and therefore the npm t command fails even though both field are part of the schema for Product in the oas/products.yml file.

So, if we remove the filed ‘type’ from product.js instead of ‘id’ the test with npm t fails again because the field ‘type’ is just like ‘id’ used by the API methods.

But then again, we might ask ourselves why did the test for the change involving ‘price’ field in section 10 pass, considering that removing the field ‘price’ should have the same effect as removing the field ‘type’ or ‘id’, because unlike the fields ‘name’ or ‘version’ they are all used by the API methods described in the oas/products.yml file?

Well, the answer to that is that those change involving the ‘price’ field in section 10 also involve removing all references for the field ‘price’ from the oas/products.yml file and not just removing of ‘price’ in the src/product.js file unlike for the changes in section 11 were only src/product.js is involved!

But these are just my interpretations and I’m not a pact expert, so take it with a grain of salt.