Pact¶
Pact between a consumer and a provider.
This module defines the classes that are used to define a Pact between a consumer and a provider. It defines the interactions between the two parties, and provides the functionality to verify that the interactions are satisfied.
As Pact is a consumer-driven contract testing tool, the consumer is responsible for defining the interactions between the two parties. The provider is then responsible for ensuring that these interactions are satisfied.
Usage¶
The main class in this module is the Pact
class. This class
defines the Pact between the consumer and the provider. It is responsible for
defining the interactions between the two parties.
The general usage of this module is as follows:
from pact.v3 import Pact
import aiohttp
pact = Pact("consumer", "provider")
interaction = pact.upon_receiving("a basic request")
interaction.given("user 123 exists")
interaction.with_request("GET", "/user/123")
interaction.will_respond_with(200)
interaction.with_header("Content-Type", "application/json")
interaction.with_body({"id": 123, "name": "Alice"})
with pact.serve() as srv:
async with aiohttp.ClientSession(srv.url) as session:
async with session.get("/user/123") as resp:
assert resp.status == 200
assert resp.headers["Content-Type"] == "application/json"
data = await resp.json()
assert data == {"id": 123, "name": "Alice"}
The repeated calls to interaction
can be chained together to define the
interaction in a more concise manner:
pact = Pact("consumer", "provider")
(
pact.upon_receiving("a basic request")
.given("user 123 exists")
.with_request("GET", "/user/123")
.will_respond_with(200)
.with_header("Content-Type", "application/json")
.with_body({"id": 123, "name": "Alice"})
)
Note that the parentheses are required to ensure that the method chaining works correctly, as this form of method chaining is not typical in Python.
Attributes¶
logger = logging.getLogger(__name__)
module-attribute
¶
Classes¶
MismatchesError(mismatches: list[dict[str, Any]])
¶
Bases: Exception
Exception raised when there are mismatches between the Pact and the server.
PARAMETER | DESCRIPTION |
---|---|
mismatches |
Mismatches between the Pact and the server. |
Source code in src/pact/v3/pact.py
Pact(consumer: str, provider: str)
¶
A Pact between a consumer and a provider.
This class defines a Pact between a consumer and a provider. It is the central class in Pact's framework, and is responsible for defining the interactions between the two parties.
One Pact
instance should be created for each provider that a consumer
interacts with. The methods on this class are used to define the broader
attributes of the Pact, such as the consumer and provider names, the Pact
specification, any plugins that are used, and any metadata that is attached
to the Pact.
Each interaction between the consumer and the provider is defined through
the upon_receiving
method, which
returns a sub-class of Interaction
.
PARAMETER | DESCRIPTION |
---|---|
consumer |
Name of the consumer.
TYPE:
|
provider |
Name of the provider.
TYPE:
|
Source code in src/pact/v3/pact.py
Attributes¶
consumer: str
property
¶
Consumer name.
provider: str
property
¶
Provider name.
specification: pact.v3.ffi.PactSpecification
property
¶
Pact specification version.
Functions¶
interactions(kind: str = 'HTTP') -> pact.v3.ffi.PactSyncHttpIterator | pact.v3.ffi.PactSyncMessageIterator | pact.v3.ffi.PactMessageIterator
¶
Return an iterator over the Pact's interactions.
The kind is used to specify the type of interactions that will be iterated over.
Source code in src/pact/v3/pact.py
messages() -> pact.v3.ffi.PactMessageIterator
¶
Iterate over the messages in the Pact.
This function returns an iterator over the messages in the Pact. This is useful for validating the Pact against the provider.
pact = Pact("consumer", "provider")
with pact.serve() as srv:
for message in pact.messages():
# Validate the message against the provider.
...
Note that the Pact must be written to a file before the messages can be iterated over. This is because the messages are not stored in memory, but rather are streamed directly from the file.
Source code in src/pact/v3/pact.py
serve(addr: str = 'localhost', port: int = 0, transport: str = 'http', transport_config: str | None = None, *, raises: bool = True, verbose: bool = True) -> PactServer
¶
Return a mock server for the Pact.
This function configures a mock server for the Pact. The mock server
is then started when the Pact is entered into a with
block:
PARAMETER | DESCRIPTION |
---|---|
addr |
Address to bind the mock server to. Defaults to
TYPE:
|
port |
Port to bind the mock server to. Defaults to
TYPE:
|
transport |
Transport to use for the mock server. Defaults to
TYPE:
|
transport_config |
Configuration for the transport. This is specific to the transport being used and should be a JSON string.
TYPE:
|
raises |
Whether to raise an exception if there are mismatches between
the Pact and the server. If set to
TYPE:
|
verbose |
Whether or not to print the mismatches to the logger. This works
independently of
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
PactServer
|
A |
Source code in src/pact/v3/pact.py
upon_receiving(description: str, interaction: Literal['HTTP', 'Sync', 'Async'] = 'HTTP') -> HttpInteraction | AsyncMessageInteraction | SyncMessageInteraction
¶
Create a new Interaction.
PARAMETER | DESCRIPTION |
---|---|
description |
Description of the interaction. This must be unique within the Pact.
TYPE:
|
interaction |
Type of interaction. Defaults to
TYPE:
|
Source code in src/pact/v3/pact.py
using_plugin(name: str, version: str | None = None) -> Self
¶
Add a plugin to be used by the test.
Plugins extend the functionality of Pact.
PARAMETER | DESCRIPTION |
---|---|
name |
Name of the plugin.
TYPE:
|
version |
Version of the plugin. This is optional and can be
TYPE:
|
Source code in src/pact/v3/pact.py
with_metadata(namespace: str, metadata: dict[str, str]) -> Self
¶
Set additional metadata for the Pact.
A common use for this function is to add information about the client library (name, version, hash, etc.) to the Pact.
PARAMETER | DESCRIPTION |
---|---|
namespace |
Namespace for the metadata. This is used to group the metadata together.
TYPE:
|
metadata |
Key-value pairs of metadata to add to the Pact. |
Source code in src/pact/v3/pact.py
with_specification(version: str | pact.v3.ffi.PactSpecification) -> Self
¶
Set the Pact specification version.
The Pact specification version indicates the features which are supported by the Pact, and certain default behaviours.
PARAMETER | DESCRIPTION |
---|---|
version |
Pact specification version. The can be either a string or a
The version string is case insensitive and has an optional
TYPE:
|
Source code in src/pact/v3/pact.py
write_file(directory: Path | str | None = None, *, overwrite: bool = False) -> None
¶
Write out the pact to a file.
This function should be called once all of the consumer tests have been run. It writes the Pact to a file, which can then be used to validate the provider.
PARAMETER | DESCRIPTION |
---|---|
directory |
The directory to write the pact to. If the directory does not exist, it will be created. The filename will be automatically generated from the underlying Pact. |
overwrite |
If set to True, the file will be overwritten if it already exists. Otherwise, the contents of the file will be merged with the existing file.
TYPE:
|
Source code in src/pact/v3/pact.py
PactServer(pact_handle: pact.v3.ffi.PactHandle, host: str = 'localhost', port: int = 0, transport: str = 'HTTP', transport_config: str | None = None, *, raises: bool = True, verbose: bool = True)
¶
Pact Server.
This class handles the lifecycle of the Pact mock server. It is responsible
for starting the mock server when the Pact is entered into a with
block, and
stopping the mock server when the block is exited.
Note that the server should not be started directly, but rather through the
serve(...)
method of a Pact
:
The URL for the server can be accessed through its
url
attribute, which will be required in
order to point the consumer client to the mock server:
pact = Pact("consumer", "provider")
with pact.serve() as srv:
api_client = MyApiClient(srv.url)
# Test the client...
If the server is instantiated with raises=True
(the default), then the
server will raise a MismatchesError
if there are mismatches in any of the
interactions. If raises=False
, then the mismatches must be handled
manually.
PARAMETER | DESCRIPTION |
---|---|
pact_handle |
Handle for the Pact.
TYPE:
|
host |
Hostname of IP for the mock server.
TYPE:
|
port |
Port to bind the mock server to. The value of
TYPE:
|
transport |
Transport to use for the mock server.
TYPE:
|
transport_config |
Configuration for the transport. This is specific to the transport being used and should be a JSON string.
TYPE:
|
raises |
Whether or not to raise an exception if the server is not matched upon exit.
TYPE:
|
verbose |
Whether or not to print the mismatches to the logger. This works
independently of
TYPE:
|
Source code in src/pact/v3/pact.py
Attributes¶
host: str
property
¶
Address to which the server is bound.
logs: str | None
property
¶
Logs from the server.
This is a string containing the logs from the server. If there are no
logs, then this is None
. For this to be populated, the logging must
be configured to make use of the internal buffer.
RAISES | DESCRIPTION |
---|---|
RuntimeError
|
If the server is not running. |
matched: bool
property
¶
Whether or not the server has been matched.
This is True
if the server has been matched, and False
otherwise.
RAISES | DESCRIPTION |
---|---|
RuntimeError
|
If the server is not running. |
mismatches: list[dict[str, Any]]
property
¶
Mismatches between the Pact and the server.
This is a string containing the mismatches between the Pact and the server. If there are no mismatches, then this is an empty string.
RAISES | DESCRIPTION |
---|---|
RuntimeError
|
If the server is not running. |
port: int
property
¶
Port on which the server is running.
If the server is not running, then this will be 0
.
transport: str
property
¶
Transport method.
url: URL
property
¶
Base URL for the server.
Functions¶
write_file(directory: str | Path | None = None, *, overwrite: bool = False) -> None
¶
Write out the pact to a file.
PARAMETER | DESCRIPTION |
---|---|
directory |
The directory to write the pact to. If the directory does not exist, it will be created. The filename will be automatically generated from the underlying Pact. |
overwrite |
Whether or not to overwrite the file if it already exists.
TYPE:
|
RAISES | DESCRIPTION |
---|---|
RuntimeError
|
If the server is not running. |
ValueError
|
If the path specified is not a directory. |