javaspring-bootjunit5pact

How to publish pact verification result to pact broker in gradle?


I have a service built with spring boot using gradle (gradle file at the bottom if needed) and Junit5. Many of the questions on stackoverflow are for maven and Junit4 and I have trouble translating the answers. My pact producer test runs and tests correctly against the contract on the broker. However the result of the successful verification is not sent to the broker. What do I have to do for that to happen?

The pact comes from 'other Service' and verifies that 'my service' correctly returns three cute cats. This is what the test looks like:

package com.miau.package;

// imports

@Provider("my_service")
@Consumer("other_service")
@PactBroker(authentication = @PactBrokerAuth(username = "pact",
    password = "${pactPassword}"), //NOSONAR hardcoded password hint no password, just variable
    host = "pact-broker.apps.home.io/", port = "443",
    tags = "sandbox"
)
@SpringBootTest(classes = Application.class,
    properties = { "spring.profiles.active=pact,fake-oauth2", "pact.verifier.publishResults=true" },
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Tag("pact")
@ExtendWith({SpringExtension.class})
public class OtherServiceContractVerifier {

    @LocalServerPort
    int port;

    @Autowired
    Application application;

    @BeforeEach
    void before(PactVerificationContext context) {
        HttpTestTarget target = new HttpTestTarget("localhost", port, "/my_service");
        context.setTarget(target);
    }

    @TestTemplate
    @ExtendWith(PactVerificationInvocationContextProvider.class)
    void executePact(PactVerificationContext context) {
        context.verifyInteraction();
    }

    @State("3 cute cats exist")
    public void stateThreecuteCatsExists() {
        // make 3 cute cats exist in database
    }
}

When running ./gradlew pactTest pactPublish everything works fine. The test passes and if I change the state to only have 2 cats, the test will fail because the pact requires the service to return 3 cats. However the pact broker does not show the successful verification. What do I need to do for that?


I have tried, but seems to be wrong:

Run ./gradlew pactVerify -> "No service providers are configured". Not sure what he needs service providers for, as the test gives all the necessary information. But after some googeling I turned up with this and added it to my build.gradle:

Pact {
broker {
    pactBrokerUrl = "https://pact-broker.apps.home.io/"
    pactBrokerUsername = "pact"
    pactBrokerPassword = pactPassword
}
serviceProviders {
    'my_service' {
        fromPactBroker {
            selectors = latestTags('Sandbox')
        }
    }
}
}

Not sure why he would need that information, it all already exists in the Pact test. but at least it changes the output of ./gradlew pactVerify, now it lists the contract and attempts to verify it only to fail with Connect to localhost:8080 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused (Connection refused) This seems to be the wrong approach as it doesn't use the existing Test at all. I haven't found how to tell it, to use the existing OtherServiceContractVerifier test.


Pact related content of gradle file (I incorperated the answer from this question to no avail):

{
    buildscript {
        if (!project.hasProperty('pactPassword')) {
            pactPassword = ''
        }
        if (!project.hasProperty('pactTags')) {
            pactTags = ''
        }
    }
}

plugins {
    id "au.com.dius.pact" version "4.1.7"
}

apply plugin: 'au.com.dius.pact'

task pactTest(type: Test) {
    environment "pactPassword", "$pactPassword"
    description = 'Runs pact tests.'
    group = 'verification'

    useJUnitPlatform()
    outputs.upToDateWhen { false }

    testClassesDirs = sourceSets.pactTest.output.classesDirs
    classpath = sourceSets.pactTest.runtimeClasspath
    shouldRunAfter test
}
check.dependsOn pactTest

dependencies {
    pactTestImplementation "au.com.dius:pact-jvm-consumer-junit5:4.0.10"
    pactTestImplementation "au.com.dius:pact-jvm-consumer-java8:4.0.10"
    pactTestImplementation "au.com.dius:pact-jvm-provider-junit5:4.0.10"
    pactTestImplementation "au.com.dius:pact-jvm-provider:4.0.10"
}

test {
    useJUnitPlatform {
        excludeTags "pact"
    }
}

pact {
    publish {
        pactBrokerUrl = "https://pact-broker.apps.home.io/"
        pactBrokerUsername = "pact"
        pactBrokerPassword = pactPassword
        tags = pactTags.tokenize(',')
    }
}

Solution

  • You seem to be mixing the Gradle verification process (./gradlew pactVerify) with JUnit one (e.g. OtherServiceContractVerifier).

    Both can be configured via

    For gradle, see https://docs.pact.io/implementation_guides/jvm/provider/gradle/#project-properties.

    For JUnit see https://docs.pact.io/implementation_guides/jvm/provider/junit/#publishing-verification-results-to-a-pact-broker

    So setting the following will enable that (note: you should only publish from CI)

    System.setProperty("pact.verifier.publishResults", "true");
    

    Example project that uses JUnit: https://github.com/pactflow/example-provider-springboot