I'm trying to write a test for one of my controller classes. In this controller, I call request.reader.text
which can throw MalformedInputException
if the body contains non-utf-8 characters.
This is the case I'm trying to test and mock in my Spock test. The easiest would be if I could mock the getReader()
method, but that turns out to be difficult.
Things I've tried:
Should work according to this post (but does not): How to mock HttpServletRequest in Spock
GrailsMockHttpServletRequest request = new GrailsMockHttpServletRequest()
request.getReader() >> {
throw new MalformedInputException(1)
}
Also tried this, as per @LeonardBrünings comment (but it seems to have no effect):
GroovySpy(GrailsMockHttpServletRequest, global: true) {
getReader() >> {
throw new MalformedInputException(1)
}
}
Reproduceable repo (run ApplicationControllerSpec
): https://github.com/Zorobay/test-app
I finally managed to find a solution after some more frantic googling. Although, this is not as clean as I would have wished, it works!
The only way I've found it possible to manipulate the request
and response
objects in a controller is by calling RequestContextHolder.setRequestAttributes()
with a new GrailsWebRequest
. The downside to this is that the response object also has to be overwritten. This is not a big problem however, as it is manipulated "in-place" when calling render()
, so we can just check the "would be" response status on our newly created object. My Spock test now looks like this:
def "validerHtml: håndterer MalformedInputException"() {
given:
String charset = "UTF-16"
GrailsMockHttpServletRequest mockRequest = Spy(GrailsMockHttpServletRequest)
mockRequest.getReader() >> {
throw new MalformedInputException(1)
}
mockRequest.setContentType("text/html;charset=${charset}")
GrailsMockHttpServletResponse mockResponse = new GrailsMockHttpServletResponse()
GrailsWebRequest webRequest = new GrailsWebRequest(mockRequest, mockResponse, mockRequest.getServletContext())
mockRequest.setAttribute(GrailsApplicationAttributes.WEB_REQUEST, webRequest)
RequestContextHolder.setRequestAttributes(webRequest) // Here we overwrite the web request
when:
controller.validateHtml()
then:
0 * controller.myService.validateMessage(*_)
// Have to check would-be response on our mocked response
mockResponse.status == HttpStatus.BAD_REQUEST.value()
mockResponse.text.startsWith("Could not read request body using charset: ${charset}")
}