Add MockMvc Kotlin DSL

This commit introduces a `MockMvc` Kotlin DSL via a set of
extensions like `MockMvc.get` or `MockMvc.request`
that provide a Kotlin idiomatic and easily discoverable
API while staying close to the original Java API design.

Closes gh-1951
This commit is contained in:
Sebastien Deleuze
2019-02-22 13:16:52 +01:00
parent b7d60b9b89
commit 0c332286f1
8 changed files with 911 additions and 0 deletions

View File

@@ -0,0 +1,208 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.servlet
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.mock.web.MockHttpSession
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder
import org.springframework.test.web.servlet.request.RequestPostProcessor
import org.springframework.util.MultiValueMap
import java.security.Principal
import java.util.*
import javax.servlet.http.Cookie
/**
* Provide a [MockHttpServletRequestBuilder] Kotlin DSL in order to be able to write idiomatic Kotlin code.
*
* @see MockMvc.get
* @see MockMvc.post
* @see MockMvc.put
* @see MockMvc.patch
* @see MockMvc.delete
* @see MockMvc.options
* @see MockMvc.request
* @author Sebastien Deleuze
* @since 5.2
*/
open class MockHttpServletRequestDsl(private val builder: MockHttpServletRequestBuilder) {
/**
* @see [MockHttpServletRequestBuilder.contextPath]
*/
var contextPath: String? = null
/**
* @see [MockHttpServletRequestBuilder.servletPath]
*/
var servletPath: String? = null
/**
* @see [MockHttpServletRequestBuilder.pathInfo]
*/
var pathInfo: String? = null
/**
* @see [MockHttpServletRequestBuilder.secure]
*/
var secure: Boolean? = null
/**
* @see [MockHttpServletRequestBuilder.characterEncoding]
*/
var characterEncoding: String? = null
/**
* @see [MockHttpServletRequestBuilder.content]
*/
var content: Any? = null
/**
* @see [MockHttpServletRequestBuilder.accept]
*/
var accept: MediaType? = null
/**
* @see [MockHttpServletRequestBuilder.accept]
*/
fun accept(vararg mediaTypes: MediaType) {
builder.accept(*mediaTypes)
}
/**
* @see [MockHttpServletRequestBuilder.contentType]
*/
var contentType: MediaType? = null
/**
* @see [MockHttpServletRequestBuilder.headers]
*/
fun headers(headers: HttpHeaders.() -> Unit) {
builder.headers(HttpHeaders().apply(headers))
}
/**
* @see [MockHttpServletRequestBuilder.header]
*/
fun header(name: String, vararg values: Any) {
builder.header(name, *values)
}
/**
* @see [MockHttpServletRequestBuilder.param]
*/
fun param(name: String, vararg values: String) {
builder.param(name, *values)
}
/**
* @see [MockHttpServletRequestBuilder.params]
*/
var params: MultiValueMap<String, String>? = null
/**
* @see [MockHttpServletRequestBuilder.cookie]
*/
fun cookie(vararg cookies: Cookie) {
builder.cookie(*cookies)
}
/**
* @see [MockHttpServletRequestBuilder.locale]
*/
fun locale(vararg locales: Locale) {
builder.locale(*locales)
}
/**
* @see [MockHttpServletRequestBuilder.requestAttr]
*/
fun requestAttr(name: String, value: Any) {
builder.requestAttr(name, value)
}
/**
* @see [MockHttpServletRequestBuilder.sessionAttr]
*/
fun sessionAttr(name: String, value: Any) {
builder.sessionAttr(name, value)
}
/**
* @see [MockHttpServletRequestBuilder.sessionAttrs]
*/
var sessionAttrs: Map<String, Any>? = null
/**
* @see [MockHttpServletRequestBuilder.flashAttr]
*/
fun flashAttr(name: String, value: Any) {
builder.flashAttr(name, value)
}
/**
* @see [MockHttpServletRequestBuilder.flashAttrs]
*/
var flashAttrs: Map<String, Any>? = null
/**
* @see [MockHttpServletRequestBuilder.session]
*/
var session: MockHttpSession? = null
/**
* @see [MockHttpServletRequestBuilder.principal]
*/
var principal: Principal? = null
/**
* @see [MockHttpServletRequestBuilder.with]
*/
fun with(processor: RequestPostProcessor) {
builder.with(processor)
}
/**
* @see [MockHttpServletRequestBuilder.merge]
*/
fun merge(parent: MockHttpServletRequestBuilder?) {
builder.merge(parent)
}
internal fun perform(mockMvc: MockMvc): ResultActionsDsl {
contextPath?.also { builder.contextPath(contextPath!!) }
servletPath?.also { builder.servletPath(servletPath!!) }
pathInfo?.also { builder.pathInfo(pathInfo) }
secure?.also { builder.secure(secure!!) }
characterEncoding?.also { builder.characterEncoding(characterEncoding!!) }
content?.also {
when (content) {
is String -> builder.content(content as String)
is ByteArray -> builder.content(content as ByteArray)
else -> builder.content(content.toString())
}
}
accept?.also { builder.accept(accept!!) }
contentType?.also { builder.contentType(contentType!!) }
params?.also { builder.params(params!!) }
sessionAttrs?.also { builder.sessionAttrs(sessionAttrs!!) }
flashAttrs?.also { builder.flashAttrs(flashAttrs!!) }
session?.also { builder.session(session!!) }
principal?.also { builder.principal(principal!!) }
return ResultActionsDsl(mockMvc.perform(builder))
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.servlet
import org.springframework.mock.web.MockMultipartFile
import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder
import javax.servlet.http.Part
/**
* Provide a [MockMultipartHttpServletRequestBuilder] Kotlin DSL in order to be able to write idiomatic Kotlin code.
*
* @see MockMvc.multipart
* @author Sebastien Deleuze
* @since 5.2
*/
class MockMultipartHttpServletRequestDsl(private val builder: MockMultipartHttpServletRequestBuilder) : MockHttpServletRequestDsl(builder) {
/**
* @see [MockMultipartHttpServletRequestBuilder.file]
*/
fun file(name: String, content: ByteArray) = builder.file(name, content)
/**
* @see [MockMultipartHttpServletRequestBuilder.file]
*/
fun file(file: MockMultipartFile) = builder.file(file)
/**
* @see [MockMultipartHttpServletRequestBuilder.part]
*/
fun part(vararg parts: Part) = builder.part(*parts)
}

View File

@@ -0,0 +1,213 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.servlet
import org.springframework.http.HttpMethod
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
import java.net.URI
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.get
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.get(urlTemplate: String, vararg vars: Any?, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.get(urlTemplate, *vars)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.get
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.get(uri: URI, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.get(uri)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.post
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.post(urlTemplate: String, vararg vars: Any?, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.post(urlTemplate, *vars)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.post
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.post(uri: URI, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.post(uri)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.put
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.put(urlTemplate: String, vararg vars: Any?, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.put(urlTemplate, *vars)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.put
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.put(uri: URI, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.put(uri)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.patch
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.patch(urlTemplate: String, vararg vars: Any?, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.patch(urlTemplate, *vars)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.patch
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.patch(uri: URI, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.patch(uri)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.delete
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.delete(urlTemplate: String, vararg vars: Any?, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.delete(urlTemplate, *vars)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.delete
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.delete(uri: URI, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.delete(uri)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.options
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.options(urlTemplate: String, vararg vars: Any?, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.options(urlTemplate, *vars)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.options
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.options(uri: URI, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.options(uri)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.request
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.request(method: HttpMethod, urlTemplate: String, vararg vars: Any?, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.request(method, urlTemplate, *vars)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.request
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.request(method: HttpMethod, uri: URI, dsl: MockHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.request(method, uri)
return MockHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockMultipartHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.multipart
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.multipart(urlTemplate: String, vararg vars: Any?, dsl: MockMultipartHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.multipart(urlTemplate, *vars)
return MockMultipartHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}
/**
* [MockMvc] extension providing access to [MockMultipartHttpServletRequestDsl] Kotlin DSL.
*
* @see MockMvcRequestBuilders.multipart
* @author Sebastien Deleuze
* @since 5.2
*/
fun MockMvc.multipart(uri: URI, dsl: MockMultipartHttpServletRequestDsl.() -> Unit = {}): ResultActionsDsl {
val requestBuilder = MockMvcRequestBuilders.multipart(uri)
return MockMultipartHttpServletRequestDsl(requestBuilder).apply(dsl).perform(this)
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.servlet
import org.springframework.test.web.servlet.result.*
import java.io.OutputStream
import java.io.Writer
/**
* Provide a [MockMvcResultHandlers] Kotlin DSL in order to be able to write idiomatic Kotlin code.
*
* @author Sebastien Deleuze
* @since 5.2
*/
class MockMvcResultHandlersDsl(private val actions: ResultActions) {
/**
* @see MockMvcResultHandlers.print
*/
fun print() {
actions.andDo(MockMvcResultHandlers.print())
}
/**
* @see MockMvcResultHandlers.print
*/
fun print(stream: OutputStream) {
actions.andDo(MockMvcResultHandlers.print(stream))
}
/**
* @see MockMvcResultHandlers.print
*/
fun print(writer: Writer) {
actions.andDo(MockMvcResultHandlers.print(writer))
}
/**
* @see MockMvcResultHandlers.log
*/
fun log() {
actions.andDo(MockMvcResultHandlers.log())
}
/**
* @see ResultActions.andDo
*/
fun handle(resultHandler: ResultHandler) {
actions.andDo(resultHandler)
}
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.servlet
import org.hamcrest.Matcher
import org.springframework.test.web.servlet.result.*
/**
* Provide a [MockMvcResultMatchers] Kotlin DSL in order to be able to write idiomatic Kotlin code.
*
* @author Sebastien Deleuze
* @since 5.2
*/
class MockMvcResultMatchersDsl(private val actions: ResultActions) {
/**
* @see MockMvcResultMatchers.request
*/
fun request(matcher: RequestResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.request().matcher())
}
/**
* @see MockMvcResultMatchers.view
*/
fun view(matcher: ViewResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.view().matcher())
}
/**
* @see MockMvcResultMatchers.model
*/
fun model(matcher: ModelResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.model().matcher())
}
/**
* @see MockMvcResultMatchers.flash
*/
fun flash(matcher: FlashAttributeResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.flash().matcher())
}
/**
* @see MockMvcResultMatchers.forwardedUrl
*/
fun forwardedUrl(expectedUrl: String?) {
actions.andExpect(MockMvcResultMatchers.forwardedUrl(expectedUrl))
}
/**
* @see MockMvcResultMatchers.forwardedUrlTemplate
*/
fun forwardedUrlTemplate(urlTemplate: String, vararg uriVars: Any) {
actions.andExpect(MockMvcResultMatchers.forwardedUrlTemplate(urlTemplate, *uriVars))
}
/**
* @see MockMvcResultMatchers.forwardedUrlPattern
*/
fun forwardedUrlPattern(urlPattern: String) {
actions.andExpect(MockMvcResultMatchers.forwardedUrlPattern(urlPattern))
}
/**
* @see MockMvcResultMatchers.redirectedUrl
*/
fun redirectedUrl(expectedUrl: String) {
actions.andExpect(MockMvcResultMatchers.redirectedUrl(expectedUrl))
}
/**
* @see MockMvcResultMatchers.redirectedUrlPattern
*/
fun redirectedUrlPattern(redirectedUrlPattern: String) {
actions.andExpect(MockMvcResultMatchers.redirectedUrlPattern(redirectedUrlPattern))
}
/**
* @see MockMvcResultMatchers.status
*/
fun status(matcher: StatusResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.status().matcher())
}
/**
* @see MockMvcResultMatchers.header
*/
fun header(matcher: HeaderResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.header().matcher())
}
/**
* @see MockMvcResultMatchers.content
*/
fun content(matcher: ContentResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.content().matcher())
}
/**
* @see MockMvcResultMatchers.jsonPath
*/
fun <T> jsonPath(expression: String, matcher: Matcher<T>) {
actions.andExpect(MockMvcResultMatchers.jsonPath(expression, matcher))
}
/**
* @see MockMvcResultMatchers.jsonPath
*/
fun jsonPath(expression: String, vararg args: Any, block: JsonPathResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.jsonPath(expression, *args).block())
}
/**
* @see MockMvcResultMatchers.xpath
*/
fun xpath(expression: String, vararg args: Any, namespaces: Map<String, String>? = null, xpathInit: XpathResultMatchers.() -> ResultMatcher) {
actions.andExpect(MockMvcResultMatchers.xpath(expression, namespaces, args).xpathInit())
}
/**
* @see MockMvcResultMatchers.cookie
*/
fun cookie(cookieInit: CookieResultMatchers.() -> ResultMatcher) {
val cookie = MockMvcResultMatchers.cookie().cookieInit()
actions.andExpect(cookie)
}
/**
* @see ResultActions.andExpect
*/
fun match(matcher: ResultMatcher) {
actions.andExpect(matcher)
}
}

View File

@@ -0,0 +1,33 @@
package org.springframework.test.web.servlet
/**
* Provide a [ResultActions] Kotlin DSL in order to be able to write idiomatic Kotlin code.
*
* @author Sebastien Deleuze
* @since 5.2
*/
class ResultActionsDsl(private val actions: ResultActions) {
/**
* Provide access to [MockMvcResultMatchersDsl] Kotlin DSL.
* @see MockMvcResultMatchersDsl.match
*/
infix fun andExpect(dsl: MockMvcResultMatchersDsl.() -> Unit): ResultActionsDsl {
MockMvcResultMatchersDsl(actions).dsl()
return this
}
/**
* Provide access to [MockMvcResultHandlersDsl] Kotlin DSL.
* @see MockMvcResultHandlersDsl.handle
*/
infix fun andDo(dsl: MockMvcResultHandlersDsl.() -> Unit): ResultActionsDsl {
MockMvcResultHandlersDsl(actions).dsl()
return this
}
/**
* @see ResultActions.andReturn
*/
fun andReturn() = actions.andReturn()
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.test.web.servlet
import org.hamcrest.CoreMatchers
import org.junit.Assert
import org.junit.Test
import org.junit.jupiter.api.assertThrows
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.test.web.Person
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import org.springframework.web.bind.annotation.*
import java.security.Principal
import java.util.*
/**
* [MockMvc] DSL tests that verifies builder, actions and expect blocks.
*
* @author Clint Checketts
* @author Petr Balat
* @author Sebastien Deleuze
*/
class MockMvcExtensionsTests {
private val mockMvc = MockMvcBuilders.standaloneSetup(PersonController()).build()
@Test
fun request() {
mockMvc.request(HttpMethod.GET, "/person/{name}", "Lee") {
secure = true
accept = MediaType.APPLICATION_JSON
headers {
contentLanguage = Locale.FRANCE
}
principal = Principal { "foo" }
} andExpect {
status { isOk }
content { contentType("application/json;charset=UTF-8") }
jsonPath("$.name") { value("Lee") }
content { json("""{"someBoolean": false}""", false) }
} andDo {
print()
}
}
@Test
fun `request without MockHttpServletRequestDsl`() {
mockMvc.request(HttpMethod.GET, "/person/{name}", "Lee") andExpect {
status { isOk }
} andDo {
print()
}
}
@Test
fun `request with custom matcher and handler`() {
var matcherInvoked = false
var handlerInvoked = false
val matcher = ResultMatcher { matcherInvoked = true }
val handler = ResultHandler { handlerInvoked = true }
mockMvc.request(HttpMethod.GET, "/person/{name}", "Lee") andExpect {
status { isOk }
} andExpect {
match(matcher)
} andDo {
handle(handler)
}
Assert.assertTrue(matcherInvoked)
Assert.assertTrue(handlerInvoked)
}
@Test
fun get() {
mockMvc.get("/person/{name}", "Lee") {
secure = true
accept = MediaType.APPLICATION_JSON
headers {
contentLanguage = Locale.FRANCE
}
principal = Principal { "foo" }
} andExpect {
status { isOk }
content { contentType("application/json;charset=UTF-8") }
jsonPath("$.name") { value("Lee") }
content { json("""{"someBoolean": false}""", false) }
} andDo {
print()
}
}
@Test
fun post() {
mockMvc.post("/person") {
content = """{ "name": "foo" }"""
headers {
accept = listOf(MediaType.APPLICATION_JSON)
contentType = MediaType.APPLICATION_JSON
}
} andExpect {
status {
isCreated
}
}
}
@Test
fun `negative assertion tests to verify the matchers throw errors when expected`() {
val name = "Petr"
mockMvc.get("/person/$name") {
accept = MediaType.APPLICATION_JSON
} andExpect {
assertThrows<AssertionError> { content { contentType(MediaType.APPLICATION_ATOM_XML) } }
assertThrows<AssertionError> { content { string("Wrong") } }
assertThrows<AssertionError> { jsonPath("name", CoreMatchers.`is`("Wrong")) }
assertThrows<AssertionError> { content { json("""{"name":"wrong"}""") } }
assertThrows<AssertionError> { jsonPath("name") { value("wrong") } }
assertThrows<AssertionError> { cookie { value("name", "wrong") } }
assertThrows<AssertionError> { flash { attribute<String>("name", "wrong") } }
assertThrows<AssertionError> { header { stringValues("name", "wrong") } }
assertThrows<AssertionError> { model { attributeExists("name", "wrong") } }
assertThrows<AssertionError> { redirectedUrl("wrong/Url") }
assertThrows<AssertionError> { redirectedUrlPattern("wrong/Url") }
assertThrows<AssertionError> { redirectedUrlPattern("wrong/Url") }
assertThrows<AssertionError> { status { isAccepted } }
assertThrows<AssertionError> { view { name("wrongName") } }
assertThrows<AssertionError> { jsonPath("name") { value("wrong") } }
}
}
@Test
fun `negative assertion tests for xpath`() {
mockMvc.get("/person/Clint") {
accept = MediaType.APPLICATION_XML
} andExpect {
status { isOk }
assertThrows<AssertionError> { xpath("//wrong") { nodeCount(1) } }
} andDo {
print()
}
}
@RestController
private class PersonController {
@GetMapping("/person/{name}")
fun get(@PathVariable name: String): Person {
return Person(name)
}
@Suppress("UNUSED_PARAMETER")
@PostMapping("/person")
@ResponseStatus(HttpStatus.CREATED)
fun post(@RequestBody person: Person) {}
}
}

View File

@@ -326,6 +326,31 @@ class UserHandler(builder: WebClient.Builder) {
Read this blog post about https://medium.com/@elizarov/structured-concurrency-722d765aa952[structured concurrency]
to understand how to run code concurrently with Coroutines.
=== MockMvc DSL
A Kotlin DSL is provided via `MockMvc` Kotlin extensions in order to provide a more idiomatic Kotlin API and to allow
better discoverability (no usage of static methods).
[source,kotlin,indent=0]
----
val mockMvc: MockMvc = ...
mockMvc.get("/person/{name}", "Lee") {
secure = true
accept = MediaType.APPLICATION_JSON
headers {
contentLanguage = Locale.FRANCE
}
principal = Principal { "foo" }
} andExpect {
status { isOk }
content { contentType("application/json;charset=UTF-8") }
jsonPath("$.name") { value("Lee") }
content { json("""{"someBoolean": false}""", false) }
} andDo {
print()
}
----
=== Kotlin Script Templates
As of version 4.3, Spring Framework provides a