-
-
Notifications
You must be signed in to change notification settings - Fork 484
Description
When writing provider tests for asynchronous pacts, I would like the @PactVerifyProvider-annotated methods on a provider test's superclass(es) to be called on the JUnit test instance, instead of a new test instance created by Pact. Only the JUnit test instance will have been properly set up by various extensions (e.g., spring dependency injection, mockito injection, etc.).
Currently, MessageTestTarget.prepareVerifier seems unnecessarily specific, only using the initialized JUnit test instance if it has the same class as the annotated method's class (m.declaringClass == testInstance.javaClass). However, the JUnit test instance can also be used if it is an instance of the annotated method's class (m.declaringClass.isInstance(testInstance)).
To demonstrate without Spring, when using pacts/some-consumer-some-provider.json, both ParentProviderTest and ChildProviderTest fail, although I would expect ChildProviderTest to succeed because it sets a compatible event. Uncommenting //context.target = fixedMessageTestTarget(packagesToScan) will make ChildProviderTest succeed, because it calls ChildProviderTest.anEvent() instead of ParentProviderTest.anEvent().
import au.com.dius.pact.core.model.Pact
import au.com.dius.pact.provider.IProviderVerifier
import au.com.dius.pact.provider.PactVerifyProvider
import au.com.dius.pact.provider.junit5.MessageTestTarget
import au.com.dius.pact.provider.junit5.PactVerificationContext
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider
import au.com.dius.pact.provider.junitsupport.IgnoreMissingStateChange
import au.com.dius.pact.provider.junitsupport.Provider
import au.com.dius.pact.provider.junitsupport.loader.PactFolder
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestTemplate
import org.junit.jupiter.api.extension.ExtendWith
import java.util.function.Function
@Provider("some-provider")
@PactFolder("pacts")
@IgnoreMissingStateChange
open class ParentProviderTest() {
var event: String = """{"id":"invalid-uuid"}"""
@TestTemplate
@ExtendWith(PactVerificationInvocationContextProvider::class)
fun testTemplate(context: PactVerificationContext) {
context.verifyInteraction()
}
class ChildProviderTest : ParentProviderTest() {
init {
event = """{"id":"12341234-1234-1234-1234-123412341234"}"""
}
}
@BeforeEach
fun beforeEach(context: PactVerificationContext) {
val packagesToScan = listOf(ParentProviderTest::class.java.packageName)
context.target = MessageTestTarget(packagesToScan)
//context.target = fixedMessageTestTarget(packagesToScan)
}
private fun fixedMessageTestTarget(packagesToScan: List<String>): MessageTestTarget = object : MessageTestTarget(packagesToScan) {
override fun prepareVerifier(
verifier: IProviderVerifier,
testInstance: Any,
pact: Pact
) {
super.prepareVerifier(verifier, testInstance, pact)
val defaultProviderMethodInstance = verifier.providerMethodInstance
verifier.providerMethodInstance = Function { m ->
if (m.declaringClass.isInstance(testInstance)) {
testInstance
} else {
defaultProviderMethodInstance.apply(m)
}
}
}
}
@PactVerifyProvider("an event")
open fun anEvent() = event
}pacts/some-consumer-some-provider.json:
{
"consumer": {
"name": "some-consumer"
},
"interactions": [
{
"comments": {
"testname": "repro.ReproConsumerTest.canHandleEvent(List)"
},
"contents": {
"content": {
"id": "e2490de5-5bd3-43d5-b7c4-526e33f71304"
},
"contentType": "application/json",
"encoded": false
},
"description": "an event",
"generators": {
"body": {
"$.id": {
"type": "Uuid"
}
}
},
"key": "499aa24f",
"matchingRules": {
"body": {
"$.id": {
"combine": "AND",
"matchers": [
{
"match": "regex",
"regex": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
}
]
}
}
},
"metadata": {
"contentType": "application/json"
},
"pending": false,
"providerStates": [
{
"name": "none"
}
],
"type": "Asynchronous/Messages"
}
],
"metadata": {
"pact-jvm": {
"version": "4.6.18"
},
"pactSpecification": {
"version": "4.0"
},
"plugins": [
]
},
"provider": {
"name": "some-provider"
}
}