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:
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user