Skip to content

Instantly share code, notes, and snippets.

@jeffsheets
Created June 20, 2014 20:18
Show Gist options
  • Star 30 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save jeffsheets/ada3de8fe4a536e5351b to your computer and use it in GitHub Desktop.
Save jeffsheets/ada3de8fe4a536e5351b to your computer and use it in GitHub Desktop.
Spock test with Mocks of Spring MVC Rest Controller using standaloneSetup and mockMvc
import groovy.json.JsonSlurper
import org.springframework.test.web.servlet.MockMvc
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.http.HttpStatus.*
import spock.lang.Specification
/**
* A Spock Spring MVC Rest unit test that doesn't require a full spring context
*/
class AccountControllerTest extends Specification {
def accountController = new AccountController()
def securityService = Mock(SecurityService)
//The magic happens here
MockMvc mockMvc = standaloneSetup(accountController).build()
def setup() {
accountController.securityService = securityService
}
def "getAccount test hits the URL and parses JSON output"() {
when: 'rest account url is hit'
def response = mockMvc.perform(get('/rest/account')).andReturn().response
def content = new JsonSlurper().parseText(response.contentAsString)
then: 'securityService correctly returned account in JSON'
1 * securityService.getCurrentLogin() >> 'spockUser'
//Testing the HTTP Status code
response.status == OK.value()
//Showing how a contains test could work
response.contentType.contains('application/json')
response.contentType == 'application/json;charset=UTF-8'
//Can test the whole content string that is returned
response.contentAsString == '{"username":"spockUser"}'
//Or can use the JsonSlurper version to test the JSON as object
content.username == 'spockUser'
}
def "simple getAccount test without spring mvc json framework"() {
when: 'getAccount is called'
def result = accountController.getAccount()
then: 'securityService correctly returns account'
1 * securityService.getCurrentLogin() >> 'spockUser'
result.username == 'spockUser'
}
}
@zedar
Copy link

zedar commented Dec 3, 2014

Thanks, very helpful gist. I used it as a base for spock unit tests in my template project for API/microservice development (java+springmvc+spock+embedded jetty+heroku) https://github.com/zedar/java-springmvc-heroku-template

@jeffsheets
Copy link
Author

awesome, that is great to hear!

@iborisov
Copy link

Hello.
Is there way to check conditions for MockMVC before checking interaction with injected service (securityService in this case)?
i.e. I don't want to see error message indicating that there was no interactions with securityService, because there was an error e.g. parsing JSON POSTed to controller - I want to check if the response status is OK first.

@jeffsheets
Copy link
Author

@iborisov in that case I would wildcard the securityService interaction to basically just stub it out like this:
_ * securityService.getCurrentLogin() >> 'spockUser'

this won't verify that getCurrentLogin() is ever called, but that could be okay for your purposes

@rsilva4-zz
Copy link

This is great! Thanks!

@xetra11
Copy link

xetra11 commented Feb 10, 2017

Where das "standaloneSetup" come from? Used the static imports you had but they dont really work

@MalikErramli
Copy link

Thanks great example!!!

@harufu
Copy link

harufu commented Nov 17, 2017

xetra11 MockMvcBuilders have standaloneSetup...

great example

@Jason-Terry
Copy link

Can you do an example with params?

Condition failed with Exception:

mvc.perform(get('/api/cards/token').params(requestParams)) .andExpect(status().isOk()) .andReturn() .response
|           |                       |      |
|           |                       |      jdk.proxy3.$Proxy66@32f5928a (renderer threw UnsupportedOperationException)
|           |                       java.lang.reflect.InvocationTargetException
|           |                       	at org.codehaus.groovy.vmplugin.v9.Java9.of(Java9.java:160)
|           |                       	at org.codehaus.groovy.vmplugin.v9.Java9.getInvokeSpecialHandle(Java9.java:179)
|           |                       	at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
|           |                       	at org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder.params(MockHttpServletRequestBuilder.java:387)
|           |                       	at controller.CardControllerSpec.get Card Token - 200(CardControllerSpec.groovy:35)
|           |                       Caused by: java.lang.IllegalAccessException: module jdk.proxy3 does not open jdk.proxy3 to unnamed module @10d307f1
|           |                       	at java.base/java.lang.invoke.MethodHandles.privateLookupIn(MethodHandles.java:259)
|           |                       	... 5 more
|           <org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder@1d416d7c method=GET url=/api/cards/token contextPath= servletPath= pathInfo= secure=null principal=null session=null characterEncoding=null content=null contentType=null headers=[:] parameters=[:] queryParams=[:] cookies=[] locales=[] requestAttributes=[:] sessionAttributes=[:] flashAttributes=[:] postProcessors=[]>
<org.springframework.test.web.servlet.MockMvc@567831a4 servlet=org.springframework.test.web.servlet.TestDispatcherServlet@271c374b filters=[] servletContext=org.springframework.mock.web.MockServletContext@3c9e187f defaultRequestBuilder=null defaultResponseCharacterEncoding=null defaultResultMatchers=[] defaultResultHandlers=[]>

@jeffsheets
Copy link
Author

@Jason-Terry unfortunately i don't have access to this project anymore, so i won't be able to easily try it out... In theory what you have here should work, so I don't know why it isn't working off the top of my head

@Jason-Terry
Copy link

I did figure it out. It was not a request parameter we were using, just confusingly handling authentication.

Now I am battling IntelliJ and its autocomplete. I can't get my code to behave when using JSON-slurper...

Code compiles, test runs and passes, but IDE doesn't understand content.response.results[0].last4 == 1234

Seems not to know what the methods are.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment