【问题标题】:Throw an exception from a grails mock method从 grails 模拟方法中抛出异常
【发布时间】:2012-03-01 20:57:43
【问题描述】:

在 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 的调用令人惊讶地返回了一个闭包。没关系将throws 声明添加到方法的签名中,也不起作用。

我认为这与 Spock 有关,但我尝试了一个类似的测试,只使用 grails 的测试混合并得到了相同的结果。这是我的尝试:

@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 的文档中的任何地方都找不到如何要求抛出异常,所以上面的代码对我来说听起来很自然。

我还发现通过谷歌搜索没有找到任何相关的东西很可疑,所以也许我在测试方面做错了事情。

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

【问题讨论】:

    标签: unit-testing testing grails mocking


    【解决方案1】:

    似乎使 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 被调用一次)。

    【讨论】:

    • 顺便说一句,我也想知道这是否是测试中的常见情况:D
    • @doelleri 也许"nullary" 是一个更常见的同义词,但我认为“niladic”听起来好多了!
    • 您的回答非常有用。但是,如果您链​​接到的问题的标题是正确的,我本可以找到它并且不会因为重复而污染 SO。没关系它是由> 27k声誉用户编写的......
    • @Esteban 好吧,有时正确描述或授权问题并不容易;基本上是因为你可能不知道出了什么问题。我链接的问题的正确标题是什么?毕竟,使用闭包和 mockFor 方法是一种奇怪的事情。如果您觉得现在您的问题是多余的,请不要;我认为这里会出现一些冗余,因为相同的问题可能会出现在不同的上下文中。您的问题很可能会在以后帮助解决该问题的人。您可能会考虑在标题中添加类似“模拟方法返回闭包”之类的内容:)
    猜你喜欢
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    相关资源
    最近更新 更多