Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 666
Esteban Avatar asked Mar 01 '12 20:03

Esteban


1 Answers

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).

like image 114
epidemian Avatar answered Oct 02 '22 10:10

epidemian