从grails mock方法中抛出异常

时间:2012-03-01 20:57:43

标签: unit-testing testing grails mocking

在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的文档中找到如何要求抛出异常,所以上面的代码听起来很自然。

我也发现可疑没有通过谷歌搜索发现任何相关信息,所以也许我在尝试做错测试。

这不是测试中的常见情况吗?您在特定方案中模拟某个方法的确定性行为,然后在发生此类方案时测试所测试方法的预期行为。抛出异常看起来对我来说是一个有效的场景。

1 个答案:

答案 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被调用一次)。