Skip to content

Commit f7aeb9d

Browse files
author
Clint Checketts
committed
Add Kotlin DSL for working with MockMvc
1 parent 25d7f09 commit f7aeb9d

File tree

5 files changed

+538
-0
lines changed

5 files changed

+538
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.web.servlet
18+
19+
import org.springframework.http.HttpMethod
20+
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder
21+
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders
22+
import java.net.URI
23+
24+
/**
25+
*
26+
* @author Clint Checketts
27+
* @author Petr Balat
28+
*/
29+
30+
/**
31+
* Create a [MockMvcRequestDsl] with the given HTTP verb.
32+
* @param method the HTTP method (GET, POST, etc)
33+
* @param urlTemplate a URL template; the resulting URL will be encoded
34+
* @param uriVars zero or more URI variables
35+
* @param block lambda for configuring [MockMvcRequestDsl]
36+
* @return the [MvcResult] (never `null`)
37+
* @since 5.1.0
38+
*
39+
*/
40+
fun MockMvc.perform(method: HttpMethod, urlTemplate:String, vararg uriVars: String, block: MockMvcRequestDsl.() -> Unit = {}): MvcResult {
41+
return performDsl(this, MockMvcRequestBuilders.request(method, urlTemplate, *uriVars), block)
42+
}
43+
44+
/**
45+
* Create a [MockMvcRequestDsl] with the given HTTP verb.
46+
* @param method the HTTP method (GET, POST, etc)
47+
* @param uri the URL
48+
* @param block lambda for configuring [MockMvcRequestDsl]
49+
* @return the [MvcResult] (never `null`)
50+
* @since 5.1.0
51+
*/
52+
fun MockMvc.perform(method: HttpMethod, uri: URI, block: MockMvcRequestDsl.() -> Unit = {}): MvcResult {
53+
return performDsl(this, MockMvcRequestBuilders.request(method, uri), block)
54+
}
55+
56+
private fun performDsl(mockMvc: MockMvc,
57+
requestBuilder: MockHttpServletRequestBuilder,
58+
block: MockMvcRequestDsl.() -> Unit = {}): MvcResult {
59+
val request = MockMvcRequestDsl(requestBuilder).apply(block)
60+
val result = mockMvc.perform(request.buildRequest())
61+
return request.applyResult(result).andReturn()
62+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.web.servlet
18+
19+
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder
20+
import org.springframework.test.web.servlet.result.*
21+
22+
23+
/**
24+
* **Main entry point for server-side Spring MVC test support.**
25+
*
26+
* ### Example
27+
*
28+
* ```
29+
* import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
30+
*
31+
* // ...
32+
*
33+
* WebApplicationContext wac = ...;
34+
*
35+
* MockMvc mockMvc = webAppContextSetup(wac).build();
36+
*
37+
* mockMvc.performGet("/form") {
38+
* expect {
39+
* status { isOk }
40+
* content { mimeType("text/html") }
41+
* forwardedUrl("/WEB-INF/layouts/main.jsp")
42+
* }
43+
* }
44+
* ```
45+
*
46+
* @constructor Creates an `MockMvcRequestDsl`.
47+
* @author Clint Checketts
48+
* @author Petr Balat
49+
*
50+
* Dsl for working with [MockMVC]
51+
*
52+
* @since 5.1.0
53+
*/
54+
class MockMvcRequestDsl(private val requestBuilder: MockHttpServletRequestBuilder) {
55+
56+
private val requestBuilders: MutableList<MockHttpServletRequestBuilder.() -> Unit> = mutableListOf()
57+
58+
private val actions: MutableList<ResultActions.() -> Unit> = mutableListOf()
59+
60+
/**
61+
* Print {@link MvcResult} details to the "standard" output stream.
62+
* @see [MockMvcResultHandlers.print]
63+
*/
64+
fun print() {
65+
actions { andDo(MockMvcResultHandlers.print()) }
66+
}
67+
68+
/**
69+
* Configure the [MockHttpServletRequestBuilder]
70+
* @param block receiver block for configuring [MockHttpServletRequestBuilder]
71+
*/
72+
fun builder(block: MockHttpServletRequestBuilder.() -> Unit) {
73+
requestBuilders.add(block)
74+
}
75+
76+
/**
77+
* Configure the [ResultActionsExpectationsDsl]
78+
* @param block receiver block for configuring request expectation via a [ResultActionsExpectationsDsl]
79+
*/
80+
fun expect(block: ResultActionsExpectationsDsl.() -> Unit) {
81+
this.actions { ResultActionsExpectationsDsl(this).apply(block) }
82+
}
83+
84+
/**
85+
* Allows adding addition post-request actions if the provided [builder] or [expect] blocks aren't sufficient
86+
* @param block receiver block for configuring additional [ResultActions]
87+
*/
88+
fun actions(block: ResultActions.() -> Unit) {
89+
this.actions.add(block)
90+
}
91+
92+
fun buildRequest(): RequestBuilder {
93+
requestBuilders.forEach { requestBuilder.apply(it) }
94+
return requestBuilder
95+
}
96+
97+
fun applyResult(result: ResultActions): ResultActions {
98+
actions.forEach { result.apply(it) }
99+
return result
100+
}
101+
102+
fun andDo(action: ResultHandler): MockMvcRequestDsl {
103+
actions { andDo(action)}
104+
return this
105+
}
106+
107+
fun andExpect(action: ResultMatcher): MockMvcRequestDsl {
108+
actions { andExpect(action)}
109+
return this
110+
}
111+
112+
fun withResult(block: MvcResult.() -> Unit) {
113+
actions { andReturn().apply(block) }
114+
}
115+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.web.servlet
18+
19+
import org.hamcrest.CoreMatchers
20+
import org.hamcrest.Matcher
21+
import org.springframework.http.HttpStatus
22+
import org.springframework.test.web.servlet.result.*
23+
24+
/**
25+
*
26+
* @author Clint Checketts
27+
* @author Petr Balat
28+
*/
29+
class ResultActionsExpectationsDsl(private val actions: ResultActions) {
30+
31+
fun status(statusInit: StatusResultMatchers.() -> ResultMatcher) {
32+
val status = MockMvcResultMatchers.status().statusInit()
33+
actions.andExpect(status)
34+
}
35+
36+
fun content(contentInit: ContentResultMatchers.() -> ResultMatcher) {
37+
val content = MockMvcResultMatchers.content().contentInit()
38+
actions.andExpect(content)
39+
}
40+
41+
fun viewName(viewName: String) {
42+
val view = MockMvcResultMatchers.view().name(viewName)
43+
actions.andExpect(view)
44+
}
45+
46+
fun model(modelInit: ModelResultMatchers.() -> ResultMatcher) {
47+
val model = MockMvcResultMatchers.model().modelInit()
48+
actions.andExpect(model)
49+
}
50+
51+
fun <T> model(name: String, modelInit: T.() -> Unit) {
52+
actions.andExpect { mvcResult ->
53+
val model = mvcResult.modelAndView?.model?.get(name) as T?
54+
model?.modelInit() ?: throw AssertionError("Model attribute $name was not found")
55+
}
56+
}
57+
58+
fun redirectedUrl(expectedUrl: String) {
59+
val header = MockMvcResultMatchers.redirectedUrl(expectedUrl)
60+
actions.andExpect(header)
61+
}
62+
63+
fun redirectedUrlPattern(redirectedUrlPattern: String) {
64+
val header = MockMvcResultMatchers.redirectedUrl(redirectedUrlPattern)
65+
actions.andExpect(header)
66+
}
67+
68+
fun header(headerInit: HeaderResultMatchers.() -> ResultMatcher) {
69+
val header = MockMvcResultMatchers.header().headerInit()
70+
actions.andExpect(header)
71+
}
72+
73+
fun flash(flashInit: FlashAttributeResultMatchers.() -> ResultMatcher) {
74+
val flash = MockMvcResultMatchers.flash().flashInit()
75+
actions.andExpect(flash)
76+
}
77+
78+
fun <T> jsonPath(expression:String, matcher : Matcher<T>) {
79+
val json = MockMvcResultMatchers.jsonPath(expression, matcher)
80+
actions.andExpect(json)
81+
}
82+
83+
fun jsonPath(expression:String, vararg args:Any, block: JsonPathResultMatchers.() -> ResultMatcher) {
84+
val xpath = MockMvcResultMatchers.jsonPath(expression, args).block()
85+
actions.andExpect(xpath)
86+
}
87+
88+
fun xpath(expression:String, vararg args:Any, xpathInit: XpathResultMatchers.() -> ResultMatcher) {
89+
val xpath = MockMvcResultMatchers.xpath(expression, args).xpathInit()
90+
actions.andExpect(xpath)
91+
}
92+
93+
fun cookie(cookieInit: CookieResultMatchers.() -> ResultMatcher) {
94+
val cookie = MockMvcResultMatchers.cookie().cookieInit()
95+
actions.andExpect(cookie)
96+
}
97+
98+
fun HttpStatus.isStatus() {
99+
status { `is`(this@isStatus.value()) }
100+
}
101+
102+
fun contentString(value: String){
103+
content { string(value) }
104+
}
105+
106+
infix fun String.jsonPath(block: JsonPathResultMatchers.() -> ResultMatcher) {
107+
actions.andExpect(MockMvcResultMatchers.jsonPath(this).block())
108+
}
109+
110+
infix fun String.jsonPathIs(value: Any?) {
111+
actions.andExpect(MockMvcResultMatchers.jsonPath(this, CoreMatchers.`is`(value)))
112+
}
113+
114+
infix fun <T> String.jsonPathMatcher(value: Matcher<T>) {
115+
actions.andExpect(MockMvcResultMatchers.jsonPath(this, value))
116+
}
117+
118+
operator fun ResultMatcher.unaryPlus(){
119+
actions.andExpect(this)
120+
}
121+
122+
fun json(jsonContent: String, strict: Boolean = false) {
123+
actions.andExpect(MockMvcResultMatchers.content().json(jsonContent, strict))
124+
}
125+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.web.servlet
18+
19+
import org.springframework.test.web.servlet.result.*
20+
21+
/**
22+
*
23+
* @author Clint Checketts
24+
* @author Petr Balat
25+
*/
26+
fun ResultActions.expectStatus(statusInit: StatusResultMatchers.() -> ResultMatcher) {
27+
val status = MockMvcResultMatchers.status().statusInit()
28+
this.andExpect(status)
29+
}
30+
31+
fun ResultActions.expectContent(contentInit: ContentResultMatchers.() -> ResultMatcher) {
32+
val content = MockMvcResultMatchers.content().contentInit()
33+
this.andExpect(content)
34+
}
35+
36+
fun ResultActions.expectViewName(viewName: String): ResultActions {
37+
val view = MockMvcResultMatchers.view()
38+
return this.andExpect(view.name(viewName))
39+
}
40+
41+
fun ResultActions.expectModel(modelInit: ModelResultMatchers.() -> ResultMatcher): ResultActions {
42+
val model = MockMvcResultMatchers.model().modelInit()
43+
return this.andExpect(model)
44+
}
45+
46+
fun <T> ResultActions.expectModel(name: String, modelInit: T.() -> Unit): ResultActions {
47+
return this.andExpect { mvcResult ->
48+
val model = mvcResult.modelAndView?.model?.get(name) as T?
49+
model?.modelInit()
50+
}
51+
}
52+
53+
fun ResultActions.expectRedirectedUrl(expectedUrl: String): ResultActions {
54+
val header = MockMvcResultMatchers.redirectedUrl(expectedUrl)
55+
return this.andExpect(header)
56+
}
57+
58+
fun ResultActions.expectRedirectedUrlPattern(redirectedUrlPattern: String): ResultActions {
59+
val header = MockMvcResultMatchers.redirectedUrl(redirectedUrlPattern)
60+
return this.andExpect(header)
61+
}
62+
63+
fun ResultActions.expectHeader(headerInit: HeaderResultMatchers.() -> ResultMatcher): ResultActions {
64+
val header = MockMvcResultMatchers.header().headerInit()
65+
return this.andExpect(header)
66+
}
67+
68+
fun ResultActions.expectFlash(flashInit: FlashAttributeResultMatchers.() -> ResultMatcher): ResultActions {
69+
val flash = MockMvcResultMatchers.flash().flashInit()
70+
return this.andExpect(flash)
71+
}
72+
73+
fun ResultActions.expectJsonPath(expression: String, vararg args: Any, jsonInit: JsonPathResultMatchers.() -> ResultMatcher): ResultActions {
74+
val json = MockMvcResultMatchers.jsonPath(expression, args).jsonInit()
75+
return this.andExpect(json)
76+
}
77+
78+
fun ResultActions.expectXPath(expression: String, vararg args: Any, xpatInit: XpathResultMatchers.() -> ResultMatcher): ResultActions {
79+
val xpath = MockMvcResultMatchers.xpath(expression, args).xpatInit()
80+
return this.andExpect(xpath)
81+
}
82+
83+
fun ResultActions.expectCookie(cookieInit: CookieResultMatchers.() -> ResultMatcher): ResultActions {
84+
val cookie = MockMvcResultMatchers.cookie().cookieInit()
85+
return this.andExpect(cookie)
86+
}

0 commit comments

Comments
 (0)