Pact-JVM Documentation

repository·master·Indexed 22 days ago

https://github.com/pact-foundation/pact-jvm

A JVM-based implementation of the Pact consumer-driven contract testing framework. It allows developers to ensure integration compatibility between services by defining expectations in consumer tests and verifying them against providers. Includes a Groovy DSL via PactBuilder and PactBodyBuilder for defining interactions, as well as a BDD-style compatibility suite using Cucumber JVM and Gradle.

Tokens
66.1K
Snippets
187
Records
261
Agent score
75%

What's inside Pact-JVM

  1. What is the Pact server?

    master

    The Pact server is a stand-alone interactions recorder and verifier designed for clients that are not based on the JVM or Ruby.

    To use it, you must implement a client for your specific platform that is responsible for:

    1. Generating JSON interactions.
    2. Running tests.
    3. Communicating with the Pact server via its REST Admin API.

    The server manages the lifecycle of mock servers, verifies interactions, writes Pact files to disk, and can publish contracts to a Pact Broker.

  2. Overview of Pact Publish

    master
    Pact Publish is a module within the Pact-JVM ecosystem designed to automate the generation and publishing of pact files to a Pact Broker. It serves as the bridge between the contract testing process (where pacts are created) and the centralized Pact Broker (where pacts are stored and managed).
  3. Overview of Pact-JVM

    master
    Pact-JVM is a JVM implementation of the Pact consumer-driven contract testing library. It allows service consumers to define HTTP requests and expected responses, which are recorded as 'pacts'. These pacts are then used by service providers to verify that they actually provide the responses the consumer expects, enabling fast integration testing via unit tests.
  4. Overview of the Pact model project

    master

    The model project is a core component of Pact-JVM that provides the underlying data structures and logic for handling pacts. It handles:

    • Pact Representation: A formal model to represent pacts.
    • Serialization/Deserialization: Converting pact models to and from transport formats.
    • Comparison: Logic to compare two parts of the pact model.
    • Library Conversion: Converting the pact model into formats required by third-party libraries used by pact-consumer and pact-provider.

    Note: You should never need to include this project directly in your build configuration. Instead, depend on the high-level pact-consumer or pact-provider modules which manage these dependencies for you.

  5. Use Pact Consumer for API Consumer testing

    master

    Pact Consumer is designed for projects that consume an API. It provides a Domain Specific Language (DSL) for Java to build consumer pacts.

    While most developers should use one of the framework-specific Pact projects (e.g., for JUnit, Spock, etc.), this module provides the core hooks and the DSL required to build pacts if you are implementing a custom testing framework.

  6. What is the Pact Specification?

    master
    The Pact Specification is a suite of tests designed to validate pact matching code. Its primary purpose is to ensure that pact library implementations across various programming languages exhibit identical matching behavior. Adhering to this specification prevents subtle interoperability issues that occur when consumers and providers use different Pact libraries.
  7. Match list items and array constraints

    master

    When dealing with JSON arrays, you can use specific DSL functions to enforce size constraints and matching rules for elements:

    Size Constraints:

    • eachLike: Ensures every item in the list matches the provided example.
    • minArrayLike(key, min): Ensures the list matches the example and has at least min items.
    • maxArrayLike(key, max): Ensures the list matches the example and has at most max items.

    Unordered Lists (V4):

    • unorderedArray: Matches the list regardless of item order.
    • unorderedMinArray / unorderedMaxArray: Matches regardless of order with size constraints.
    • unorderedMinMaxArray: Matches regardless of order with both min and max constraints.

    Array Contains (V4):

    • arrayContaining(key): Matches the array against a set of required variants. The matching succeeds if each variant occurs at least once in the array (order does not matter).
    // Example: Ensuring a list of users has at least 2 items with specific types
    DslPart body = new PactDslJsonBody()
        .minArrayLike("users", 2)
            .id()
            .stringType("name")
        .closeObject()
        .closeArray();
  8. Displaying external references from Pact interactions

    master

    When using V4 Pact files that contain external references (e.g., OpenAPI operation IDs or Jira tickets), the verification reporters include this metadata in their output. The format depends on the reporter used:

    • Console (ANSI): Indented text under a References: header.
    • SLF4J: Logged at INFO level with an indented structure.
    • Markdown report: A nested list immediately following the interaction description.
    • JSON report: Included under the path consumer.comments.references in the output JSON.
  9. Manage provider states using a state change URL

    master

    You can instruct the provider to switch to a specific state before an interaction by providing a stateChangeUrl. The verifier will send a POST request to this URL containing the providerState description and any parameters.

    Configuration Options

    • stateChangeUrl: The URL to receive the state change request.
    • stateChangeUsesBody: Determines how data is sent.
      • true (default): Data is sent as a JSON body: { "state" : "...", "params": { ... } }.
      • false: Data is passed as query parameters.
    • stateChangeRequestFilter: A closure to manipulate the state change request itself (e.g., adding auth headers).

    Teardown

    Set stateChangeTeardown = true on the provider to enable teardown calls. The verifier will call the URL with an action parameter set to setup before the test, and action=teardown after the test.

    pact {
        serviceProviders {
            provider1 {
                hasPactWith('consumer1') {
                    pactFile = file('path/to/provider1-consumer1-pact.json')
                    stateChangeUrl = url('http://localhost:8001/tasks/pactStateChange')
                    stateChangeUsesBody = false // defaults to true
                    stateChangeRequestFilter = { req ->
                        req.addHeader('Authorization', 'OAUTH ...')
                    }
                }
            }
        }
    }
  10. How BDD and Declarative styles work in Kotlin DSL

    master

    The Kotlin DSL supports two ways to define interactions:

    1. BDD Style: Uses given at the top level (before the interaction) and uponReceiving to define the interaction. given applies to the next interaction block. You can call given multiple times to attach multiple provider states to a single interaction.

    2. Declarative Style: Uses interaction as the entry point and declares given states inside the interaction block. This keeps provider states and the interaction co-located.

    Note: uponReceiving and interaction are aliases and can be used interchangeably.

    // BDD Style
    pact(consumer = "C", provider = "P") {
        given("state 1")
        given("state 2")
        uponReceiving("description") {
            // ...
        }
    }
    
    // Declarative Style
    pact(consumer = "C", provider = "P") {
        interaction("description") {
            given("state 1")
            // ...
        }
    }
  11. Understand the Matcher selection algorithm

    master

    When multiple matcher paths could apply to a single item (due to the * wildcard), Pact selects the most specific one using a weighting system. The path with the highest total weight is chosen.

    Weighting Rules:

    • Root node ($): 2
    • Matching property name: 2
    • Matching array index: 2
    • Star (*) matching a property or index: 1
    • Non-matching element or 'everything else': 0

    Example Calculation: For the path $.item1.level[1].id:

    • $ (2) * .item1 (2) * .level (2) * [1] (2) * .id (2) = 32

    For the path $.*.level[*].id:

    • $ (2) * .* (1) * .level (2) * [*] (1) * .id (2) = 8