Course outline

API Testing / Advanced: versioned evidence and review / Lesson 14

Test the consumer-provider boundary

Separate consumer request construction, response interpretation, and provider verification.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain why a passing mock does not establish provider compatibility.
  • Define focused interactions and provider states without installing tools.

Identify the integration misunderstanding

A consumer can construct the wrong path or misread a field even when its own unit tests pass against a friendly fake. A provider can satisfy its general schema while no longer meeting a specific supported consumer need. Contract testing addresses the shared messages at this boundary. Begin with an actual consumer responsibility, such as requesting a public book title and handling the documented missing-book outcome. Avoid importing the provider’s entire business test suite into the consumer contract; persistence and internal decision correctness belong to provider functional tests.

Exercise the real consumer transformation

A consumer-side test should use the request-building and response-reading code whose assumptions matter. The local example injects a transport replacement, verifies the requested method and path, and returns a minimal synthetic response. It then checks the consumer’s title extraction. This gives useful evidence about the client function, while the replacement still represents an assumption about the provider. It is not a Pact execution and produces no interoperable contract file. The explicit boundary prevents a local pass from being mistaken for a provider verification result.

python Check one consumer interaction locally
def title_for(book_id, transport):
    result = transport("GET", "/books/" + book_id)
    return result["title"]

def fake_transport(method, path):
    assert (method, path) == ("GET", "/books/book-4")
    return {"id": "book-4", "title": "Quiet Rivers"}

assert title_for("book-4", fake_transport) == "Quiet Rivers"
print("consumer transformation checked")
Expected output
consumer transformation checked

The complete program checks request construction for a safe fixed identifier and response extraction. The transport is a Python function, not an HTTP connection. Encoding arbitrary identifiers and actual provider responses require additional evidence.

Define the provider state independently

An interaction needs a controlled provider state, such as book-4 exists with a public title. That state should be established by an approved fixture mechanism during provider verification, not inferred from mutable shared environment data. The non-runnable example records the interaction in an intentionally custom format. It is a review artifact, not valid Pact syntax. Match only the fields the consumer genuinely depends on, while retaining necessary constraints such as identifier relationships and value types. Excessively exact timestamps or unrelated fields make contracts brittle without protecting consumer behavior.

json A custom interaction-review record
{"artifactFormat":"classroom-interaction-v1","consumer":"reading-panel","provider":"public-catalog","providerState":"book-4-exists","request":{"method":"GET","path":"/books/book-4"},"responseNeeds":{"status":200,"requiredFields":["id","title"],"id":"book-4","titleType":"string"}}

This JSON is deliberately not a Pact specification. It documents one consumer expectation and provider-state assumption. No broker, mock server, provider verifier, or publication action is run.

Bind evidence to the versions that participated

A provider verification result must identify the provider build and the consumer contract version it checked. A green result from an old interaction artifact does not establish compatibility with a newly changed consumer. Keep supported consumer versions and environment assumptions visible in the release decision. A contract tool can organize this evidence, but it cannot choose organizational support policy automatically. Contract checks also leave deployment routing, network trust, runtime configuration, and some data behavior to other tests. Distinguish those remaining boundaries from the message compatibility claim.

Combine contract and functional evidence

For creating an entry, a consumer contract can establish agreement about the request and response, while a provider functional test establishes that the correct entry and effects are committed. Keep both claims because they answer different questions. Include meaningful error interactions the consumer actually handles, but avoid duplicating every provider validation permutation. When an interaction fails, determine whether the consumer assumption, provider behavior, or fixture state is wrong before updating the expected message. A changed artifact is a reviewed contract decision, not a convenient way to silence disagreement.

Common errors and fixes

A friendly mock hides the wrong path

Why it happens
The replacement does not inspect the outgoing request.
How to fix it
Verify method, path, and relevant serialization through the real client code.
Prevent it next time
Review consumer transformations and provider verification together.

An old green contract result approves a new consumer

Why it happens
The evidence is not bound to artifact versions.
How to fix it
Associate results with the exact consumer contract and provider build.
Prevent it next time
Keep a versioned compatibility record for supported consumers.

Contract tests claim correct persistence

Why it happens
Message agreement is confused with functional effects.
How to fix it
Add provider state and side-effect assertions at the proper boundary.
Prevent it next time
State the separate purpose of each test layer.

Check your understanding

1. A client uses only id and title. Should its contract freeze every provider field?

Show worked solution

Usually no. Specify the fields and relationships necessary for the supported consumer, plus meaningful request and error behavior. Freezing unrelated fields creates needless coupling. Provider schema and functional tests can cover their own broader promises without turning this consumer interaction into a full provider specification.

2. The consumer test passes against the injected transport. What remains unknown?

Show worked solution

Whether the actual supported provider can produce that response for the stated provider state, and whether transport configuration and deployment wiring work. Record the local client result separately, then obtain provider verification and authorized integration evidence for those boundaries.

Key takeaways

  • A mock pass establishes a consumer assumption, not provider agreement.
  • Provider states and artifact versions make interactions reproducible.
  • Message compatibility and business correctness need separate assertions.

Official references