JUnit 5 support for Pact consumer tests
The library is available on maven central using:
- group-id =
- artifact-id =
- version-id =
To write Pact consumer tests with JUnit 5, you need to add
@ExtendWith(PactConsumerTestExt) to your test class. This
PactRunner used for JUnit 4 tests. The rest of the test follows a similar pattern as for JUnit 4 tests.
2. create a method annotated with
@Pact that returns the interactions for the test#
For each test (as with JUnit 4), you need to define a method annotated with the
@Pact annotation that returns the
interactions for the test.
3. Link the mock server with the interactions for the test with
Then the final step is to use the
@PactTestFor annotation to tell the Pact extension how to setup the Pact test. You
can either put this annotation on the test class, or on the test method. For examples see
@PactTestFor annotation allows you to control the mock server in the same way as the JUnit 4
allows you to set the hostname to bind to (default is
localhost) and the port (default is to use a random port). You
can also set the Pact specification version to use (default is V3).
NOTE on the hostname: The mock server runs in the same JVM as the test, so the only valid values for hostname are:
|binds to the address that localhost points to (normally the loopback adapter)|
|binds to the loopback adapter|
|host name||binds to the default interface that the host machines DNS name resolves to|
|binds to the all interfaces on the host machine|
If you set the
providerName on the
@PactTestFor annotation, then the first method with a
@Pact annotation with the
same provider name will be used. See ArticlesTest for
If you set the
pactMethod on the
@PactTestFor annotation, then the method with the provided name will be used (it still
@Pact annotation). See MultiTest for an example.
You can get the mock server injected into the test method by adding a
MockServer parameter to the test method.
This helps with getting the base URL of the mock server, especially when a random port is used.
By default, pact files are written to
build/pacts if you use Gradle), but this can be overwritten with the
pact.rootDir system property.
This property needs to be set on the test JVM as most build tools will fork a new JVM to run the tests.
For Gradle, add this to your build.gradle:
For maven, use the systemPropertyVariables configuration:
You can override the directory the pacts are written in a test by adding the
@PactDirectory annotation to the test
By default, when the pact file is written, it will be merged with any existing pact file. To force the file to be
overwritten, set the Java system property
You can have values from the provider state callbacks be injected into most places (paths, query parameters, headers, bodies, etc.). This works by using the V3 spec generators with provider state callbacks that return values. One example of where this would be useful is API calls that require an ID which would be auto-generated by the database on the provider side, so there is no way to know what the ID would be beforehand.
The following DSL methods all you to set an expression that will be parsed with the values returned from the provider states:
For JSON bodies, use
For headers, use
For query parameters, use
For paths, use
For example, assume that an API call is made to get the details of a user by ID. A provider state can be defined that specifies that the user must be exist, but the ID will be created when the user is created. So we can then define an expression for the path where the ID will be replaced with the value returned from the provider state callback.
You can also just use the key instead of an expression:
Overriding the expression markers
You can change the markers of the expressions using the following system properties:
You can enable a HTTPS mock server by setting
https=true on the
@PactTestFor annotation. Note that this mock
server will use a self-signed certificate, so any client code will need to accept self-signed certificates.
You can provide your own KeyStore file to be loaded on the MockServer. In order to do so you should fulfill the
privateKeyPassword on the
Please bear in mind you should also enable HTTPS flag.
It is advisable to focus on a single interaction with each test, but you can enable multiple providers in a single test. In this case, a separate mock server will be started for each configured provider.
To enable this:
- Create a method to create the Pact for each provider annotated with the
@Pact(provider = "....")annotation. The provider name must be set on the annotation. You can create as many of these as required, but each must have a unique provider name.
- In the test method, use the
pactMethodsattribute on the
@PactTestForannotation with the names of all the methods defined in step 1.
- Add a MockServer parameter to the test method for each provider configured in step 1 with a
@ForProviderannotation with the name of the provider.
- In your test method, interact with each of the mock servers passed in step 3. Note that if any mock server does not get the requests it expects, it will fail the test.
For an example, see MultiProviderTest.
As each test will get a new mock server, connections can not be persisted between tests. HTTP clients can cache connections with HTTP/1.1, and this can cause subsequent tests to fail. See #342 and #1383.
One option (if the HTTP client supports it, Apache HTTP Client does) is to set the system property
the test JVM. The other option is to set
true to force the mock server to
Connection: close header with every response (supported with Pact-JVM 4.2.7+).
For testing a consumer of messages from a message queue using JUnit 5 and Pact V4, see AsyncMessageTest.
You can also use matching rules for the metadata associated with the message. There is a
MetadataBuilder class to
help with this. You can access it via the
withMetadata method that takes a Java Consumer on the