Reputation: 2579
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
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