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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With