如何在 Spock 控制器测试中模拟 Grails 请求对象方法
How to mock Grails request object method in Spock controller test
我正在尝试为我的控制器之一编写测试 类。在这个控制器中,我调用 request.reader.text
如果正文包含非 utf-8 字符,它会抛出 MalformedInputException
。
这就是我在 Spock 测试中尝试测试和模拟的情况。最简单的方法是模拟 getReader()
方法,但事实证明这很困难。
我尝试过的事情:
应该根据这个post工作(但不是):
GrailsMockHttpServletRequest request = new GrailsMockHttpServletRequest()
request.getReader() >> {
throw new MalformedInputException(1)
}
也试过这个,根据@LeonardBrünings 的评论(但似乎没有效果):
GroovySpy(GrailsMockHttpServletRequest, global: true) {
getReader() >> {
throw new MalformedInputException(1)
}
}
可复制回购 (运行 ApplicationControllerSpec
): https://github.com/Zorobay/test-app
经过更疯狂的谷歌搜索,我终于设法找到了解决方案。虽然,这不像我希望的那样干净,但它有效!
我发现可以在控制器中操作 request
和 response
对象的唯一方法是使用新的 GrailsWebRequest
调用 RequestContextHolder.setRequestAttributes()
。这样做的缺点是响应对象也必须被覆盖。然而,这不是一个大问题,因为它是在调用 render()
时“就地”操作的,所以我们可以只检查新创建的对象上的“将是”响应状态。我的 Spock 测试现在看起来像这样:
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}")
}
我正在尝试为我的控制器之一编写测试 类。在这个控制器中,我调用 request.reader.text
如果正文包含非 utf-8 字符,它会抛出 MalformedInputException
。
这就是我在 Spock 测试中尝试测试和模拟的情况。最简单的方法是模拟 getReader()
方法,但事实证明这很困难。
我尝试过的事情:
应该根据这个post工作(但不是):
GrailsMockHttpServletRequest request = new GrailsMockHttpServletRequest()
request.getReader() >> {
throw new MalformedInputException(1)
}
也试过这个,根据@LeonardBrünings 的评论(但似乎没有效果):
GroovySpy(GrailsMockHttpServletRequest, global: true) {
getReader() >> {
throw new MalformedInputException(1)
}
}
可复制回购 (运行 ApplicationControllerSpec
): https://github.com/Zorobay/test-app
经过更疯狂的谷歌搜索,我终于设法找到了解决方案。虽然,这不像我希望的那样干净,但它有效!
我发现可以在控制器中操作 request
和 response
对象的唯一方法是使用新的 GrailsWebRequest
调用 RequestContextHolder.setRequestAttributes()
。这样做的缺点是响应对象也必须被覆盖。然而,这不是一个大问题,因为它是在调用 render()
时“就地”操作的,所以我们可以只检查新创建的对象上的“将是”响应状态。我的 Spock 测试现在看起来像这样:
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}")
}