Using Pact for integration tests
Pact is a tool which allows us to easily write and validate contract tests. We use it to mock requests during unit tests on the consumer application (in this case, Sirius), record those mocks, and then run them against the provider (e.g. LPA Code Generator, Notify, HTML to PDF) to verify that they can be satisfied.
In doing so, we can validate tests on both sides of the integration without having to run the applications (and their dependencies) simultaneously.
Pact process in Sirius
There are two main Pact components in Sirius: a mock service which acts as the provider during tests, and a PHP library to configure and interact with the container.
The test lifecycle is as follows:
- At the start of the test suite, PHP connects to the mock service and resets it
- Each test details the anticipated requests and responses that will take place
during it. For example, you might anticipate a
POST
to/emails/send
and then call$emailService->sendMail($address)
- After each test, PHP asks the mock service too confirm all requests/responses were made. If not, the test fails.
- At the end of the test suite, PHP asks the mock service to provide a summary of the requests/responses from all tests in the suite. This is provided in a JSON file matching the Pact specification
- If a URL and basic auth credentials are supplied, PHP uploads this file to a Pact broker. This will then send the file to providers to test with
This is designed to be reusable, so we can set up a test suite per-provider and each will generate a separate JSON Pact file.
Adding a new integration
Firstly, create a new test suite in phpunit.xml
. Because the JSON file is
generated at the end of each suite, we need one suite per integration. Add the
suite name to the arguments of the PactTestListener
in the same XML file.
Then write your unit tests. Each test should specify what requests it should make and what responses are expected back. Be specific with the requests (to ensure you are sending the right thing) and open with the responses (using matchers).
Make sure to verify the registered requests at the end of each test. It’s perfectly valid to have tests which don’t make any requests.
Lastly, you need to run your tests as part of the api-unit-pact
make command
(or a separate command if you need to). This requires starting up the pact-mock
service as your provider and running your unit test suite with suitable
environment variables. An example is shown below for integrating with a service
called “pepperoni”:
api-unit-pact:
PACT_PROVIDER_NAME=lpa-codes docker-compose --project-name api-unit-pact up -d pact-mock
docker-compose --project-name api-unit-pact \
-f docker-compose.yml \
$(DOCKER_FEATURE_FILES) \
run \
--no-deps \
--volume ${PWD}/build/output/$(SUITE):/output \
-e PACT_BROKER_URI \
-e PACT_BROKER_HTTP_AUTH_USER \
-e PACT_BROKER_HTTP_AUTH_PASS \
-e PACT_CONSUMER_VERSION \
-e PACT_CONSUMER_TAG=v1_production \
--rm api-app \
vendor/bin/phpunit \
--configuration=tests/phpunit.xml \
--exclude-group=functional \
--testsuite=pact-lpa-codes \
--log-junit=/output/api-unit-pact.xml
+
+ PACT_PROVIDER_NAME=pepperoni docker-compose --project-name api-unit-pact up -d pact-mock
+ docker-compose --project-name api-unit-pact \
+ -f docker-compose.yml \
+ $(DOCKER_FEATURE_FILES) \
+ run \
+ --no-deps \
+ --volume ${PWD}/build/output/$(SUITE):/output \
+ -e PACT_BROKER_URI \
+ -e PACT_BROKER_HTTP_AUTH_USER \
+ -e PACT_BROKER_HTTP_AUTH_PASS \
+ -e PACT_CONSUMER_VERSION \
+ -e PACT_CONSUMER_TAG=production \
+ --rm api-app \
+ vendor/bin/phpunit \
+ --configuration=tests/phpunit.xml \
+ --exclude-group=functional \
+ --testsuite=pact-pepperoni \
+ --log-junit=/output/api-unit-pact.xml
docker-compose --project-name api-unit-pact stop pact-mock
Verifying Pacts
Sirius also verifies the contracts expected by opg-sirius-user-management as part of the Jenkins build. Locally, you can verify that the pacts created by the opg-sirius-user-management tests will work by doing something like:
$ make dev-up
$ docker-compose run -p 9000:8080 -d pact-proxy
$ pact-provider-verifier <PATH_TO_PACTS>/sirius-user-management-sirius.json \
--provider-base-url=http://localhost:9000 \
--provider-app-version=1.0.0 \
--provider-states-setup-url=http://localhost:9000/pact-setup