Contract testing met Pactflow (deel 3/3) : Provider test

Zie ook:
Contract testing met Pactflow (deel 1/3) : Contract test process
Contract testing met Pactflow (deel 2/3) : Consumer test
Contract testing met Pactflow (deel 3/3) : Provider test

In deze blog laat ik een voorbeeld zien hoe je als provider microservice een contract test kunt maken. Hierbij ga ik er vanuit dat je Jenkins gebruikt en een account hebt bij pactflow die je gebruikt als pact-broker. De code is in Kotlin.

Voeg onderstaande dependency toe aan de pom.xml

<dependency>
    <groupId>au.com.dius.pact.provider</groupId>
    <artifactId>junit5</artifactId>
    <version>4.1.7</version>
    <scope>test</scope>
</dependency>

Voeg onderstaande variabele toe in de environment stap in de Jenkinsfile:

PACTFLOW_TOKEN = credentials('jenkins-pactflowtoken')

(Hierbij is het nodig dat er een ‘jenkins-pactflowtoken’ secret in Jenkins is aangemaakt met daarin het token dat je van pactflow gekregen hebt)

Verander de “compile & test” stap in onderstaande code:

stage('Compile & Test') {
  steps {
    sh '''
        unset JAVA_TOOL_OPTIONS
        GIT_COMMIT=$(git rev-parse HEAD)
        PUBLISH_PACT_RESULT=false
        TEST_PENDING_CONTRACTS=false
        # Only the master branch must publish the pact results, and test all pending contracts
        if [[ $BRANCH_NAME == "master" ]]; then
            PUBLISH_PACT_RESULT=true
            TEST_PENDING_CONTRACTS=true
        fi
        ./mvnw install -Dpact.provider.version=$GIT_COMMIT -Dpact.verifier.publishResults=$PUBLISH_PACT_RESULT -Dpact.provider.tag=$BRANCH_NAME -Dpactbroker.enablePending=$TEST_PENDING_CONTRACTS
    '''
  }
}

Voorbeeld unit test voor de verificatie van de contracts:

import Customer
import CustomerDatabase
import Rest
import au.com.dius.pact.provider.junit5.HttpTestTarget
import au.com.dius.pact.provider.junit5.PactVerificationContext
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider
import au.com.dius.pact.provider.junitsupport.IgnoreNoPactsToVerify
import au.com.dius.pact.provider.junitsupport.Provider
import au.com.dius.pact.provider.junitsupport.State
import au.com.dius.pact.provider.junitsupport.loader.PactBroker
import au.com.dius.pact.provider.junitsupport.loader.PactBrokerAuth
import au.com.dius.pact.provider.junitsupport.loader.VersionSelector
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.*
import org.junit.jupiter.api.extension.ExtendWith

@Provider("sample-service-2")
@IgnoreNoPactsToVerify
@PactBroker(
    host = "xxx.pactflow.io",
    scheme = "https",
    port = "443",
    authentication = PactBrokerAuth(token = "\${PACTFLOW_TOKEN}"),
    consumerVersionSelectors = [
        VersionSelector(tag = "master"),
        VersionSelector(tag = "\${BRANCH_NAME:DIGI-201}") // change this to the current branch if you want to test that contract
    ],
    enablePendingPacts = "\${pactbroker.enablePending:false}",
    providerTags = ["\${BRANCH_NAME:master}"],
    includeWipPactsSince = "2020-01-01"
)

class ContractVerificationTest {
    private val customerDatabase = mockk<CustomerDatabase>()
    private val restModule = Rest(9099, customerDatabase)

    @TestTemplate
    @ExtendWith(PactVerificationInvocationContextProvider::class)
    internal fun pactVerificationTestTemplate(context: PactVerificationContext?) {
        context?.verifyInteraction()
    }

    @BeforeEach
    internal fun before(context: PactVerificationContext?) {
        context?.target = HttpTestTarget("localhost", 9099, "/")
        restModule.start()
    }

    @AfterEach
    internal fun after(){
        restModule.stop()
    }

    @State("default")
    internal fun default(params: Map<String, Boolean>) {
        val customerExists = (params.getOrDefault("customerExists", true))
        val error = (params.getOrDefault("failure", false))
        when {
            error == true -> {
                every { customerDatabase.findCustomer(any()) } throws RuntimeException("Database is down")
            }
            customerExists == false -> {
                every { customerDatabase.findCustomer(any()) } returns null
            }
            customerExists == true -> {
                every { customerDatabase.findCustomer(any()) } returns Customer()
            }
        }
    }

}

Webhook:

Je kunt in pactflow een webhook aanmaken om er voor te zorgen dat een jenkins build automatisch gaat lopen als er een nieuw contract voor deze provider op gitflow geupload wordt. Pactflow zal de build alleen triggeren als het contract daadwerkelijk veranderd is t.o.v vorige versies.

2 gedachtes over “Contract testing met Pactflow (deel 3/3) : Provider test

Reacties zijn gesloten.