Skip to content

Commit d26555d

Browse files
author
Ronald Holshausen
committedFeb 22, 2020
feat: created a Spring JUnit 5 module #1023
1 parent 6bf77f3 commit d26555d

File tree

6 files changed

+88
-2
lines changed

6 files changed

+88
-2
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Pact Spring/JUnit5 Support
2+
3+
This module extends the base [Pact JUnit5 module](../pact-jvm-provider-junit5). See that for more details.
4+
5+
For writing Spring Pact verification tests with JUnit 5, there is an JUnit 5 Invocation Context Provider that you can use with
6+
the `@TestTemplate` annotation. This will generate a test for each interaction found for the pact files for the provider.
7+
8+
To use it, add the `@Provider` and `@ExtendWith(SpringExtension.class)` and one of the pact source annotations to your test class (as per a JUnit 5 test), then
9+
add a method annotated with `@TestTemplate` and `@ExtendWith(PactVerificationSpringProvider.class)` that
10+
takes a `PactVerificationContext` parameter. You will need to call `verifyInteraction()` on the context parameter in
11+
your test template method.
12+
13+
For example:
14+
15+
```java
16+
@ExtendWith(SpringExtension.class)
17+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
18+
@Provider("Animal Profile Service")
19+
@PactBroker
20+
public class ContractVerificationTest {
21+
22+
@TestTemplate
23+
@ExtendWith(PactVerificationSpringProvider.class)
24+
void pactVerificationTestTemplate(PactVerificationContext context) {
25+
context.verifyInteraction();
26+
}
27+
28+
}
29+
```
30+
31+
You will now be able to setup all the required properties using the Spring context, e.g. creating an application
32+
YAML file in the test resources:
33+
34+
```yaml
35+
pactbroker:
36+
host: your.broker.host
37+
auth:
38+
username: broker-user
39+
password: broker.password
40+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
dependencies {
2+
implementation project(path: ":provider:pact-jvm-provider-junit5", configuration: 'default')
3+
implementation 'org.springframework:spring-context:5.2.3.RELEASE'
4+
implementation 'org.springframework:spring-test:5.2.3.RELEASE'
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package au.com.dius.pact.provider.spring.junit5
2+
3+
import au.com.dius.pact.core.support.expressions.ValueResolver
4+
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider
5+
import org.junit.jupiter.api.extension.ExtensionContext
6+
import org.springframework.test.context.TestContextManager
7+
import org.springframework.test.context.junit.jupiter.SpringExtension
8+
9+
class PactVerificationSpringProvider() : PactVerificationInvocationContextProvider() {
10+
11+
override fun getValueResolver(context: ExtensionContext): ValueResolver? {
12+
val store = context.root.getStore(ExtensionContext.Namespace.create(SpringExtension::class.java))
13+
val testClass = context.requiredTestClass
14+
val testContextManager = store.getOrComputeIfAbsent(testClass, { TestContextManager(testClass) },
15+
TestContextManager::class.java)
16+
val environment = testContextManager.testContext.applicationContext.environment
17+
return SpringEnvironmentResolver(environment)
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package au.com.dius.pact.provider.spring.junit5
2+
3+
import au.com.dius.pact.core.support.expressions.SystemPropertyResolver
4+
import au.com.dius.pact.core.support.expressions.ValueResolver
5+
import org.springframework.core.env.Environment
6+
7+
class SpringEnvironmentResolver(private val environment: Environment) : ValueResolver {
8+
override fun resolveValue(property: String?): String? {
9+
val tuple = SystemPropertyResolver.PropertyValueTuple(property).invoke()
10+
return environment.getProperty(tuple.propertyName, tuple.defaultValue)
11+
}
12+
13+
override fun propertyDefined(property: String) = environment.containsProperty(property)
14+
}

‎provider/pact-jvm-provider-junit5/src/main/kotlin/au/com/dius/pact/provider/junit5/PactJUnit5VerificationProvider.kt

+9-2
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ class PactVerificationStateChangeExtension(
356356
* Main TestTemplateInvocationContextProvider for JUnit 5 Pact verification tests. This class needs to be applied to
357357
* a test template method on a test class annotated with a @Provider annotation.
358358
*/
359-
class PactVerificationInvocationContextProvider : TestTemplateInvocationContextProvider {
359+
open class PactVerificationInvocationContextProvider : TestTemplateInvocationContextProvider {
360360
override fun provideTestTemplateInvocationContexts(context: ExtensionContext): Stream<TestTemplateInvocationContext> {
361361
logger.debug { "provideTestTemplateInvocationContexts called" }
362362

@@ -374,7 +374,12 @@ class PactVerificationInvocationContextProvider : TestTemplateInvocationContextP
374374
logger.debug { "Verifying pacts for provider '$serviceName' and consumer '$consumerName'" }
375375

376376
val pactSources = findPactSources(context).flatMap {
377-
filterPactsByAnnotations(it.load(serviceName), context.requiredTestClass).map { pact -> pact to it.pactSource }
377+
val valueResolver = getValueResolver(context)
378+
if (valueResolver != null) {
379+
it.setValueResolver(valueResolver)
380+
}
381+
val pacts = it.load(serviceName)
382+
filterPactsByAnnotations(pacts, context.requiredTestClass).map { pact -> pact to it.pactSource }
378383
}.filter { p -> consumerName == null || p.first.consumer.name == consumerName }
379384

380385
val tests = pactSources.flatMap { pact ->
@@ -388,6 +393,8 @@ class PactVerificationInvocationContextProvider : TestTemplateInvocationContextP
388393
return tests.stream() as Stream<TestTemplateInvocationContext>
389394
}
390395

396+
protected open fun getValueResolver(context: ExtensionContext): ValueResolver? = null
397+
391398
private fun validateStateChangeMethods(testClass: Class<*>) {
392399
val errors = mutableListOf<String>()
393400
AnnotationSupport.findAnnotatedMethods(testClass, State::class.java, HierarchyTraversalMode.TOP_DOWN).forEach {

‎settings.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ include 'provider:pact-jvm-provider-maven'
2525
include 'provider:pact-jvm-provider-junit'
2626
include 'provider:pact-jvm-provider-junit5'
2727
include 'provider:pact-jvm-provider-spring'
28+
include 'provider:pact-jvm-provider-junit5-spring'
2829

2930
if (JavaVersion.current().isJava8()) {
3031
include 'provider:pact-jvm-provider-lein'

0 commit comments

Comments
 (0)
Please sign in to comment.