Skip to content

Commit

Permalink
feat(Junit5+Spring): support injecting MockHttpServletRequestBuilder …
Browse files Browse the repository at this point in the history
…when using MockMvc tests #1334
  • Loading branch information
Ronald Holshausen committed Mar 28, 2021
1 parent bed5ba5 commit 3622c25
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ import java.io.File
/**
* JUnit 5 test extension class used to inject parameters and execute the test for a Pact interaction.
*/
class PactVerificationExtension(
private val pact: Pact<Interaction>,
private val pactSource: au.com.dius.pact.core.model.PactSource,
private val interaction: Interaction,
private val serviceName: String,
private val consumerName: String?,
private val propertyResolver: ValueResolver = SystemPropertyResolver
open class PactVerificationExtension(
val pact: Pact<Interaction>,
val pactSource: au.com.dius.pact.core.model.PactSource,
val interaction: Interaction,
val serviceName: String,
val consumerName: String?,
val propertyResolver: ValueResolver = SystemPropertyResolver
) : TestTemplateInvocationContext, ParameterResolver, BeforeEachCallback, BeforeTestExecutionCallback,
AfterTestExecutionCallback {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,11 @@ class MockMvcTestTarget @JvmOverloads constructor(

private fun toMockRequestBuilder(request: Request): MockHttpServletRequestBuilder {
val body = request.body
return if (body.isPresent()) {
val cookies = cookies(request)
val servletRequestBuilder: MockHttpServletRequestBuilder = if (body.isPresent()) {
if (request.isMultipartFileUpload()) {
val multipart = MimeMultipart(ByteArrayDataSource(body.unwrap(), request.contentTypeHeader()))
val multipartRequest = MockMvcRequestBuilders.fileUpload(requestUriString(request))
val multipartRequest = MockMvcRequestBuilders.multipart(requestUriString(request))
var i = 0
while (i < multipart.count) {
val bodyPart = multipart.getBodyPart(i)
Expand All @@ -98,18 +99,20 @@ class MockMvcTestTarget @JvmOverloads constructor(
multipartRequest.file(MockMultipartFile(name, filename, bodyPart.contentType, bodyPart.inputStream))
i++
}
multipartRequest.headers(mapHeaders(request, true)).cookie(*cookies(request))
multipartRequest.headers(mapHeaders(request, true))
} else {
MockMvcRequestBuilders.request(HttpMethod.valueOf(request.method), requestUriString(request))
.headers(mapHeaders(request, true))
.content(body.value)
.cookie(*cookies(request))
}
} else {
MockMvcRequestBuilders.request(HttpMethod.valueOf(request.method), requestUriString(request))
.headers(mapHeaders(request, false))
.cookie(*cookies(request))
}
if (cookies.isNotEmpty()) {
servletRequestBuilder.cookie(*cookies)
}
return servletRequestBuilder
}

private fun cookies(request: Request): Array<Cookie> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package au.com.dius.pact.provider.spring.junit5

import au.com.dius.pact.core.model.Interaction
import au.com.dius.pact.core.model.Pact
import au.com.dius.pact.core.model.PactSource
import au.com.dius.pact.provider.junit5.PactVerificationContext
import au.com.dius.pact.provider.junit5.PactVerificationExtension
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.api.extension.ParameterContext
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder

class PactVerificationSpringExtension(
pact: Pact<Interaction>,
pactSource: PactSource,
interaction: Interaction,
serviceName: String,
consumerName: String?
) : PactVerificationExtension(pact, pactSource, interaction, serviceName, consumerName) {
constructor(context: PactVerificationExtension) : this(context.pact, context.pactSource, context.interaction,
context.serviceName, context.consumerName)

override fun supportsParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Boolean {
val store = extensionContext.getStore(ExtensionContext.Namespace.create("pact-jvm"))
val testContext = store.get("interactionContext") as PactVerificationContext
return when (parameterContext.parameter.type) {
MockHttpServletRequestBuilder::class.java -> testContext.target is MockMvcTestTarget
else -> super.supportsParameter(parameterContext, extensionContext)
}
}

override fun resolveParameter(parameterContext: ParameterContext, extensionContext: ExtensionContext): Any? {
val store = extensionContext.getStore(ExtensionContext.Namespace.create("pact-jvm"))
return when (parameterContext.parameter.type) {
MockHttpServletRequestBuilder::class.java -> store.get("request")
else -> super.resolveParameter(parameterContext, extensionContext)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package au.com.dius.pact.provider.spring.junit5

import au.com.dius.pact.core.support.expressions.ValueResolver
import au.com.dius.pact.provider.junit5.PactVerificationExtension
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.api.extension.TestTemplateInvocationContext
import org.springframework.test.context.TestContextManager
import org.springframework.test.context.junit.jupiter.SpringExtension
import java.util.stream.Stream

class PactVerificationSpringProvider() : PactVerificationInvocationContextProvider() {

Expand All @@ -16,4 +19,14 @@ class PactVerificationSpringProvider() : PactVerificationInvocationContextProvid
val environment = testContextManager.testContext.applicationContext.environment
return SpringEnvironmentResolver(environment)
}

override fun provideTestTemplateInvocationContexts(context: ExtensionContext): Stream<TestTemplateInvocationContext> {
return super.provideTestTemplateInvocationContexts(context).map {
if (it is PactVerificationExtension) {
PactVerificationSpringExtension(it)
} else {
it
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,37 @@ 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 org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.http.HttpStatus
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder
import org.springframework.web.bind.annotation.CookieValue
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestController

@WebMvcTest(controllers = [ CookieResource ])
@Provider("CookieService")
@PactFolder("pacts")
@Provider('CookieService')
@PactFolder('pacts')
class MockMvcTestWithCookieSpec {

@Autowired
MockMvc mockMvc

@BeforeEach
void before(PactVerificationContext context) {
context?.target = new MockMvcTestTarget(null, [ new CookieResource() ], [], [], true)
}

@TestTemplate
@ExtendWith(PactVerificationSpringProvider)
void pactVerificationTestTemplate(PactVerificationContext context) {
void pactVerificationTestTemplate(PactVerificationContext context, MockHttpServletRequestBuilder request) {
request.header('test', 'test')
context?.verifyInteraction()
}

@RestController
static class CookieResource {
@GetMapping(value = '/cookie', produces = 'text/plain')
@ResponseStatus(HttpStatus.OK)
String getData(@RequestParam('id') String id, @CookieValue("token") String token) {
String getData(@RequestParam('id') String id, @CookieValue('token') String token) {
assert token != null && !token.empty
"Hello $id $token"
}
Expand Down

0 comments on commit 3622c25

Please sign in to comment.