DEV Community

Artem Ptushkin
Artem Ptushkin

Posted on • Edited on

Consumer and provider binding in contract-testing

I believe the fact that you are using contract-testing already has brought you here.

This approach seems simple for the first look but brings new questions and discoveries upon getting into it.

One of them is the understanding of how actually the contract corresponds with the consumer and provider.

Let's consider HTTP integration as a classic one and Pact as a consumer-driven-contracts framework here but Spring Cloud Contract follows the same rules.

The contract will be always used as a stub on the consumer side and as a set of validation criteria on the provider side

1_TCch2EAD4JSDkFhWOhM3ew

How does it affect me?

Each time you run consumer contract tests, it uses the contract data to start on it a stub server with expectations on a request and prepared stub data for response.

Each time you run provider tests, it uses the contract test to build a request to your actual server. Then it verifies the actual response against a set of validation criteria in the contact.

What's actually might be interesting here is to get an understanding of the concept of the strictness of the request/response data.

Request

Consider, you expect that a server accepts your authorization header with a Bearer JWT token.

Speaking without code: I expect when my app calls you with any valid JWT token you respond 200

Header:
  Authorization: Bearer eyJraWQiOiJ0aGlzLWlzLXJ
Enter fullscreen mode Exit fullscreen mode

Consumer

You might not care about the strictness of the request data, i.e. you can use a stub that expects: any JWT bearer token

It means that matters only the format of data and not the data itself.

Provider

The request must be strict otherwise, the framework won't be able to build an actual request.

Options:

  • Framework generates a random value
  • Consumer prepare an example that will be used as a strict value

Having random values can be viable for some cases, but it leaves uncertainty as the example, that comes with the contract, will be non-informative.

In other words, the data of the request is crucial technically. And it is better to keep it strict as opposed to random.

That's why Pact framework has this option to provide the example for any data or not, btw.

Response

Vice versa for the response.

The consumer must receive strict values in the response from the stub server.

The provider can respond with something that matches some data by a patter.

request response
consumer not strict
provider strict not

The reference in the contract

That's when you put the expectations like this:

.matchHeader("Authorization", "Bearer.*", "Bearer eyJraWQiOiJ0aGlzLWlzLXJ")
Enter fullscreen mode Exit fullscreen mode

Where the second parameter is the regexp that you expect to match the header.

It will be converted in the pact to the scrict values:

"request" {
  "method": "GET",
  "path": "/your/path",
  "headers": {
          "Authorization": "Bearer eyJraWQiOiJ0aGlzLWlzLXJ"
    }
}
Enter fullscreen mode Exit fullscreen mode

Plus matchingRules that come from the regexp property we passed above:

"matchingRules": {
          "header": {
            "Authorization": {
              "matchers": [
                {
                  "match": "regex",
                  "regex": "Bearer.*"
                }
              ],
              "combine": "AND"
            }
...
Enter fullscreen mode Exit fullscreen mode

Having the table above and the pact you can link them now and refer to this in your investigations.

request response
consumer matchingRules strict values
provider strict values matchingRules

Thinking about the format and data it is also right to consider it like this:

request response
consumer format data
provider data format

Sure, don't forget that for 'data' you can use random values.

Conclusions

Here I'd like to remind you that contract testing is the testing by the example approach. Thus, if you pay attention to the examples and understand the logic behind them, it will help you to have a great set of request/response samples that you can share with your teammates in combination with tests.

For more reference about the strict request and loose response read about Robustness principle.

I think one of the most important parts of understanding contract testing is the behavior of stubs and verifications. Hope this note can help you to think through this concept.

PS. I wrote about the contract testing approach here. Please join for more.

Top comments (0)