Consumer-Driven Contract Testing with Pact for Angular and Spring Boot
Setting up Contract Testing using Pact, Angular with Karma and Jest and Spring Boot with JUnit 5
When setting up Contract testing for our project we had some issues getting Pact working nicely with Angular Testbed and Karma/Jest. The code examples that are available are either outdated or simply not working when having multiple providers.
In this article I will go step by step showing how to setup a Consumer-Driven Contract Testing framework with Pact. It will include an Angular frontend as a Consumer and a Spring Boot backend as a Provider.
I have created an example repository on GitHub containing all the code:
This code provides examples how to setup contract testing using Angular as a Consumer and Spring Boot as a Provider…
Creating the Consumer
Since the framework is consumer-driven we will start with our first consumer, the Angular frontend. We will both use Karma and Jest to run the Pact tests.
To create the first Angular app we will use Angular CLI. First create a directory
consumers from the root dir and in this directory run:
ng new angular-karma
Keep every setting default and the Angular app will be created
As you can see above we will create an Angular app per testrunner to keep things clear. We will start with Karma.
Adding the service
To have something to contract test we will add a User service to our Angular project. Go to the
src/app folder and create the
user.service.ts file. It will be a simple service for our User endpoint:
Setting up Pact using Karma
Install the following packages:
npm install --save-dev @pact-foundation/karma-pact @pact-foundation/pact-node @pact-foundation/pact-web
At this time there is still an issue with the
@pact-foundation/karma-pactplugin not working with Karma 4, so we need to lower the Karma version to
karma.conf.js file in the root of the Angular project:
The important things to note about
- the used specification version
- which port the Pact mock service will be running
- where the contracts will be written. Since we will not be using a Pact broker for this guide, we will use a shared directory in the root folder to share contract between Consumers and Providers.
Also note the
proxies part that makes sure our calls get proxied to the Pact mock server.
npm run test /
yarn test to start the Karma testrunner. It will start the Pact mock server:
INFO: firstname.lastname@example.org/9882 on hades.local:
Creating Pact Server with options:
INFO [pact]: Pact Mock Server running on port: 1234
Since we don’t have any Contract tests yet this is all Pact will do for now
Adding Consumer Contract Test
To integrate closely with Angular we will write our Contract tests next to the service. To separate it from unit tests we will call it
To write our contract test we first need to setup the Pact framework. To use Pact with Karma we need to use
PactWeb instead of the
Pact Node.js library. In the
beforeAll we add a new
PactWeb configuration for this service:
This configuration determines which Consumer/Provider pair is contract tested. The port number is for the port on which the Pact mock server should be available.
We will use Angular TestBed to setup our service for testing:
Next are the callbacks for verifying the mock service and writing the contract file:
With all this plumbing we can create our first contract test:
beforeAll we setup the mock service to accept a GET request on the
/api/users/1 path and return an example user we defined above. The test will then call our Angular service and validate the expected response is returned.
When we now run
ng test a contract file is generated in the root
pacts folder. If you view this file you can see it contains our definition of the contract as defined by our test code for this Consumer/Provider pair:
Setting up Pact using Jest
When using Jest instead of Karma there are some setup changes, but the contract tests stay the same.
Create a new Angular app from the root dir using
ng new angular-jest .
Add the same
user.service.ts as shown for the Karma framework.
Then install the following packages:
npm install --save-dev @angular-builders/jest @pact-foundation/pact @pact-foundation/pact-node @types/jest jest jest-preset-angular
jest.pact.config.js file in the root of the Angular project:
Things to note in this config are the
testUrl param, which makes sure all our calls will be directed to our Pact mock server. Also we have a setupFile that will setup our Jest framework. It’s located in
To make sure Jest will work we need to edit the
tsconfig.spec.json and add the
experimentalDecorators tags. This prevent errors with the
jest-preset-angular package as stated here:
The final file to edit will be
angular.json . Default Angular uses Karma instead of Jest for testing. Find the
test part in the json and change it to:
Things to note here are the
runInBand parameter to make sure Jest will run the Pact tests sequentially instead of parallel.
Adding Consumer Contract Test
This step is mostly the same as for our Karma setup, with a few minor changes. We will be using the
Pact Node.js library instead. First setup the Pact mock server:
The other steps are the same as for Karma:
After this the contract test is exactly the same as in the Karma framework:
Now we can run the contract test using
Creating the Provider
Since we now have our Consumers and their contracts we can create the Provider. We will use Spring Boot for that.
Setup Spring Boot
I used the Spring Initializr site to create the base for the Provider. Create a Maven project using Java. Fill in the required fields and then extract it to the
You can run the backend service using
mvn clean spring-boot:run
Adding User Service
We will add a new RestController to handle our request for the User Service:
We also will need a model for User:
Setting up Pact using JUnit 5
To setup our contract verification we will use the JUnit 5 Pact extension.
First add the following packages to your pom file:
To make use of our contracts in the root folder we include them in our
testResources so we can acces them from the Java classpath:
Setting up the contract verification is now very simple:
Things to note:
@Providerannotation refers to the Provider name, it has to match the Provider name used in the Consumer test. It will only test contracts that match the Provider name.
@PactFolderrefers to the folder the test can find the contracts.
startwill start our Spring Boot application.
- In the
beforemethod we point Pact to the correct base url where the Provider is available.
@Stateannotation provides a method to setup our backend to reach that state. In our case we don’t need do to anything.
- Finally in the
pactVerificationTestTemplatemethod the contracts are verified.
In this guide we created an Angular frontend and Spring Boot backend. We then proceeded to create a contract from the Angular frontend and verified that it abides the contract. We then verified the contract for the Spring boot backend.
In this guide we haven’t looked at Spring Cloud Contract, which is another framework to setup contract testing for Spring Boot applications. But it is not mutually exclusive since Spring Cloud Contract can convert contracts to Pact versions.