在Grails的控制器单元测试(更具体地说是Spock ControllerSpec
)上,我想在协作者抛出异常时检查测试方法的行为。
我正在使用mockFor实用程序(来自Spock的UnitSpec或Grails的GrailsUnitTestMixin)来指定我对测试中这种异常抛出方法的要求,如下所示:
@TestFor(TestController)
class TestControllerSpec extends Specification {
def "throwing and exception from a mock method should make the test fail"() {
setup:
def serviceMock = mockFor(TestService)
serviceMock.demand.exceptionThrowingMethod() { throw new Exception() }
controller.testService = serviceMock.createMock()
when:
controller.triggerException()
then:
thrown(Exception)
}
}
所以,在triggerException
里面,我调用exceptionThrowingMethod
,就像这样:
class TestController {
def testService
def triggerException() {
testService.exceptionThrowingMethod()
}
}
但测试失败了:
预期的异常java.lang.Exception,但没有抛出异常
我调试了执行并且异常没有被抛出,exceptionThrowingMethod
的调用令人惊讶地返回了一个Closure。没关系将throws
声明添加到方法的签名中也无效。
我认为这与Spock有关,但我尝试使用grails的测试mixins进行了一次simliar测试并得到了相同的结果。这是我的尝试:
@TestFor(TestController)
class TestControllerTests {
void testException() {
def serviceMock = mockFor(TestService)
serviceMock.demand.exceptionThrowingMethod() { throw new Exception() }
controller.testService = serviceMock.createMock()
shouldFail(Exception) {
controller.triggerException()
}
}
}
我的代码中发现了什么问题吗?
我无法在Grails的文档中找到如何要求抛出异常,所以上面的代码听起来很自然。
我也发现可疑没有通过谷歌搜索发现任何相关信息,所以也许我在尝试做错测试。
这不是测试中的常见情况吗?您在特定方案中模拟某个方法的确定性行为,然后在发生此类方案时测试所测试方法的预期行为。抛出异常看起来对我来说是一个有效的场景。
答案 0 :(得分:9)
似乎使demand
闭包为niladic(即没有隐式it
参数,带有明确的->
)does the trick:
serviceMock.demand.exceptionThrowingMethod {-> throw new Exception() }
更新:您也可以使用Groovy的本地MockFor
类,它似乎不需要这种闭包怪异:
@TestFor(TestController)
class TestControllerTests {
void testException() {
def mock = new MockFor(TestService)
mock.demand.exceptionThrowingMethod { throw new Exception() }
controller.testService = mock.proxyInstance()
shouldFail { controller.triggerException() }
mock.verify(controller.testService)
}
}
请注意,在不使用mock.use
时,必须使用mock.verify
来验证模拟约束(即exceptionThrowingMethod
被调用一次)。