Esteban
Esteban

Reputation: 2579

Throw an exception from a grails mock method

On a Grails' controller unit test (more specifically a Spock ControllerSpec), I'd like to check the behavior of the tested method when a collaborator throws and exception.

I'm using the mockFor utility (either from Spock's UnitSpec or Grails' GrailsUnitTestMixin) to specify my demands for such exception-throwing method in the test, like this:

@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)
    }
}

So, inside triggerException I invoke exceptionThrowingMethod, like this:

class TestController {

    def testService

    def triggerException() {
        testService.exceptionThrowingMethod()
    }
}

But the test is failing like:

Expected exception java.lang.Exception, but no exception was thrown

I debugged the excecution and the exception is not beign thrown, the invokation of exceptionThrowingMethod surprisingly returns a Closure. Nevermind adding the throws declaration to the method's signature, won't work either.

I thought this was related to Spock, but I tried a simliar test using just grails' test mixins and got the same result. This was my attempt:

@TestFor(TestController)
class TestControllerTests {

    void testException() {
        def serviceMock = mockFor(TestService)
        serviceMock.demand.exceptionThrowingMethod() { throw new Exception() }
        controller.testService = serviceMock.createMock()

        shouldFail(Exception) {
            controller.triggerException()
        }
    }
}

Do you find anything wrong in my code?

I couldn't find at any point in Grails' docs how to demand an exception to be thrown, so the above code sounded natural to me.

I also find it suspicious not finding anything related by googling, so maybe I'm trying to do the wrong thing regarding testing.

Isn't this a common case in testing? You mock some method's deterministic behaviour in a specific scenario, and then test the expected behaviour of the method under test when such a scenario occurs. Throwing an exception looked like a valid scenario to me.

Upvotes: 5

Views: 6949

Answers (1)

epidemian
epidemian

Reputation: 19219

It seems that making the demand closure niladic (i.e. having no implicit it argument, with an explicit ->) does the trick:

serviceMock.demand.exceptionThrowingMethod {-> throw new Exception() }

Update: you may also use Groovy's native MockFor class, which, it seems, doesn't require this closure weirdness:

@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)
    }
}

Notice that when not using mock.use, mock.verify has to be used in order to verify the mock constraints (i.e. that exceptionThrowingMethod was called once).

Upvotes: 10

Related Questions