如何在 Spock 控制器测试中模拟 Grails 请求对象方法
Posted
技术标签:
【中文标题】如何在 Spock 控制器测试中模拟 Grails 请求对象方法【英文标题】:How to mock Grails request object method in Spock controller test 【发布时间】:2022-01-04 10:45:36 【问题描述】:我正在尝试为我的一个控制器类编写测试。在这个控制器中,我调用request.reader.text
,如果正文包含非utf-8 字符,它可以抛出MalformedInputException
。
这就是我试图在我的 Spock 测试中测试和模拟的情况。最简单的方法是我可以模拟 getReader()
方法,但事实证明这很困难。
我尝试过的事情:
应该根据这篇文章工作(但不):How to mock HttpServletRequest in Spock
GrailsMockHttpServletRequest request = new GrailsMockHttpServletRequest()
request.getReader() >>
throw new MalformedInputException(1)
也试过这个,根据@LeonardBrünings 的评论(但它似乎没有效果):
GroovySpy(GrailsMockHttpServletRequest, global: true)
getReader() >>
throw new MalformedInputException(1)
可重现的 repo(运行 ApplicationControllerSpec
): https://github.com/Zorobay/test-app
【问题讨论】:
请编辑您的问题,提供MCVE,而不仅仅是迷你测试sn-p。可重复的测试用例极大地提高了您快速获得有用答案的机会。 @kriegaex 好了 :) 我现在可以重现这种情况,但我以前从未使用过 Grails 或其特殊的测试支持。我看到这个请求已经是某种特殊的模拟了。也许可以以某种方式配置该模拟,但您也注意到,没有直接设置阅读器的方法,这意味着只读。我想我在这里超出了我的深度,我不想开始考虑 Groovy 元类技巧。 Traits 也包含在 Grails 测试中,这并没有让事情变得更容易。也许另一种 Grails 测试类型更适合,我不知道。其他人可以更好地帮助你,对不起。 您可以使用全局GroovySpy
,因为 grails 中的所有内容都使用 Groovy。
@LeonardBrünings 我不确定我将如何完成这项工作。我试过这个,但它似乎没有效果(代码添加到问题描述中)。
【参考方案1】:
经过一番疯狂的谷歌搜索后,我终于设法找到了解决方案。虽然,这并不像我希望的那样干净,但它确实有效!
我发现可以在控制器中操作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")
【讨论】:
别忘了在 build.groovy 文件中需要这个:compile "org.grails:grails-test"
以上是关于如何在 Spock 控制器测试中模拟 Grails 请求对象方法的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spock 进行 Grails 测试 - 选择哪个模拟框架?
Grails / Spock:如何在类中模拟从类本身调用方法的单个方法?
IntelliJ IDEA 的零覆盖:带有 Spock 单元测试的 Grails
在 Intellij Idea 中运行 grails 2.1.3 测试:Spock 测试中出现奇怪错误:无法添加域类 [class x.y.Z]。它不是域