Spock Framework Mocks allow to easily test handling of unexpected behaviors and inspect thrown exceptions. See how to *throw and handle expected exceptions in unit tests!
System under test
Here’s a part of our system that we want to examine. It consists of only two parts: UserController and UserService.
You can imagine that UserService implementation will do some logic of adding a user somewhere:
package com.farenda.tutorials.spock; public interface UserService { boolean exists(User user); void add(User user); }
The REST Controller just takes incoming objects and interacts with the service:
package com.farenda.tutorials.spock; //@RestController and other annotations removed for brevity public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } public void addUser(String name) { if (!userService.exists(name)) { userService.add(new User(name)); } } }
Testing exception handling
Sometimes there’s a need to test handling of exceptions in code and we would like to throw them from Mock. This example shows how to do that:
package com.farenda.tutorials.spock import spock.lang.Specification class MockThrowExceptionTest extends Specification { // an interface with two methods: exists(user), add(user) def userService = Mock(UserService) // a controller to test, that will use mock of the service: def controller = new UserController(userService) def 'should throw exception for invalid username'() { given: def username = 'Joffrey Baratheon' userService.exists(_ as User) >> false userService.add(_ as User) >> { User user -> throw new IllegalArgumentException(user.name) } when: controller.addUser(username) then: def e = thrown(IllegalArgumentException) e.message == username } }
In the example, the return value for exists() method could have been omitted, because the default value is false anyway.
The important point here is that we throw an exception from Groovy closure and expect it using Spock’s thrown(Type) method. A nice thing is that we can assign the exception to a variable and assert its data.
When exception is not thrown
When the exception is not thrown, then Spock will print the following error:
Expected exception of type 'java.lang.IllegalArgumentException', but no exception was thrown at org.spockframework.lang.SpecInternals.checkExceptionThrown(SpecInternals.java:79) at org.spockframework.lang.SpecInternals.thrownImpl(SpecInternals.java:66) at com.farenda.solved.MockThrowExceptionTest.should throw exception for invalid username(MockThrowExceptionTest.groovy:26)
Expect no exceptions to be thrown
Of course there is also complementary method that allows to assert that an exception has not been thrown:
def 'should not throw'() { when: controller.addUser(null) then: notThrown(IllegalArgumentException) // other assertions }
Now, you’ve got another tool in your Spock testing toolbox! :-)