CLOUD CONCEPT

Contract Testing

Contract testing verifies that communicating components satisfy agreed expectations for requests, responses, or messages at their integration boundaries.

Cloud Concepts Hub →

What is Contract Testing

A contract defines the externally observable behavior that a consumer expects from a provider, including data formats, required fields, status codes, and relevant interaction rules. Contract tests catch incompatible changes early and make mocked dependencies more trustworthy, reducing reliance on slow or fragile end-to-end tests.

Contract testing checks whether independently developed components can communicate according to an agreed interface. A consumer is the component making a request or processing a message; a provider supplies the response or publishes the message. Their contract can describe HTTP methods, paths, headers, request bodies, response fields, error formats, and message schemas. The objective is to detect incompatible assumptions at the boundary rather than verify every internal business rule.

For example, an order application might call an external payment API and expect a successful authorization response containing a string authorizationId and a recognized status value. Consumer tests can run against a mock API that returns these agreed responses. They should verify that the application sends the expected request and correctly handles representative success and error responses. However, passing against a mock proves compatibility only with that mock. Provider verification must separately establish that the real implementation satisfies the same expectations.

Contracts can originate from a provider-owned specification, such as an OpenAPI document, or from executable consumer expectations. In a consumer-driven workflow, consumer tests produce an interaction contract that the provider verifies against its implementation. A specification-driven workflow can validate requests and responses against a shared interface definition. Neither approach should rely solely on manually maintained example payloads, because those examples can drift from actual behavior.

In cloud development environments, configure external dependency endpoints so applications can use isolated mock APIs instead of production systems. A mock server can run locally, in a build container, or behind a dedicated development endpoint. Amazon API Gateway REST APIs also support mock integrations for returning configured responses without calling a backend. Such mocks are useful test doubles, but they do not automatically verify compatibility with the real external provider. Keep credentials and test data separate from production, and avoid live operations that charge customers or modify real accounts.

A practical pipeline runs consumer tests against controlled mocks, publishes versioned contract artifacts, and runs provider verification when the provider is under the team's control. Fail the relevant build or deployment gate when required interactions become incompatible. For third-party APIs that cannot execute your contracts, use published specifications and sandbox checks where available, recognizing that the resulting assurance is weaker than coordinated provider verification.

Choose assertions carefully. Removing a required field, changing a numeric value to a string, or changing an expected status code can break consumers. Adding an optional response field is often compatible, but strict deserializers can still reject it. Prefer assertions about required behavior over exact equality of entire payloads when extra fields are intentionally allowed. Include agreed error responses and distinguish a valid error payload from transport failures such as timeouts.

Contract tests complement rather than replace integration and end-to-end tests. An integration test exercises components together, while a contract test specifically checks their boundary agreement; some tests serve both purposes. Contract verification does not establish production networking, IAM permissions, TLS configuration, latency, or availability. Keep a smaller set of tests against real development or sandbox dependencies to cover those risks. The main trade-off is faster, more deterministic feedback in exchange for maintaining contracts, representative fixtures, and verification workflows.

Key aspects of Contract Testing

Contract testing combines explicit interface expectations, trustworthy test doubles, provider verification, and automated compatibility checks.

Explicit boundary expectations

Define the requests, responses, or messages that components agree to exchange. Include required fields, types, status codes, headers, and relevant error behavior rather than only successful example payloads.

Consumer and provider verification

Test consumer behavior against agreed interactions, then verify that the provider implementation satisfies those interactions. A consumer passing against an unverified mock is not evidence that the real integration remains compatible.

Controlled external dependencies

Use configurable mock endpoints to make development tests deterministic and avoid production side effects. Keep mocks aligned with verified contracts or authoritative interface specifications.

Compatibility-focused assertions

Assert the behavior consumers actually require without unnecessarily fixing unrelated implementation details. Check whether schema changes remain compatible with real consumer parsing behavior.

Automated deployment checks

Run contract checks in continuous integration and associate results with specific application and contract versions. Configure deployment gates to reject incompatible changes before promotion.

Complementary test coverage

Retain real integration tests for credentials, networking, serialization, and dependency configuration. Contract tests provide focused compatibility feedback but do not prove operational readiness.

Cloud services for Contract Testing

API Gateway can expose a controlled mock REST endpoint for development tests, while Lambda functions can implement the application components being tested. CodeBuild runs the chosen testing framework against mock interactions and provider implementations, producing compatibility results and versioned artifacts. CodePipeline sequences these checks and prevents promotion when a required verification action fails. These services supply execution, endpoint, and orchestration capabilities rather than a complete contract-testing system. Teams must still define contracts, select testing tools, maintain representative scenarios, and verify actual provider behavior. Separate integration tests should exercise deployed permissions, networking, and service configuration.

Amazon API Gateway image Amazon API Gateway

REST API mock integrations can return configured responses without invoking a backend, supporting development tests against external dependency substitutes. Request validators can check configured request parameters and body models, but neither mock integrations nor request validation provide complete consumer-provider contract verification.

Open Amazon API Gateway →
AWS CodeBuild image AWS CodeBuild

Run contract-testing frameworks, start mock servers, and execute consumer or provider verification in build environments. Configure test commands to fail the build when compatibility checks fail, and publish reports or contract artifacts for later stages.

Open AWS CodeBuild →
AWS CodePipeline image AWS CodePipeline

Orchestrate contract checks alongside application build and deployment stages. A failed verification action can stop pipeline progression so an incompatible application version is not promoted through that pipeline.

Open AWS CodePipeline →
AWS Lambda image AWS Lambda

Lambda functions can be consumers or providers whose HTTP or event payload boundaries need verification. Test handler-level contracts quickly, then retain deployed integration tests for invocation permissions, event-source behavior, and API mappings.

Open AWS Lambda →