How can exceptions be tested in a nice way (e.g. data tables) with Spock?
Example: Having a method validateUser
that can throw exceptions with different messages or no exception if the user is valid.
The specification class itself:
class User { String userName } class SomeSpec extends spock.lang.Specification { ...tests go here... private validateUser(User user) { if (!user) throw new Exception ('no user') if (!user.userName) throw new Exception ('no userName') } }
Variant 1
This one is working but the real intention is cluttered by all the when / then labels and the repeated calls of validateUser(user)
.
def 'validate user - the long way - working but not nice'() { when: def user = new User(userName: 'tester') validateUser(user) then: noExceptionThrown() when: user = new User(userName: null) validateUser(user) then: def ex = thrown(Exception) ex.message == 'no userName' when: user = null validateUser(user) then: ex = thrown(Exception) ex.message == 'no user' }
Variant 2
This one is not working because of this error raised by Spock at compile time:
Exception conditions are only allowed in 'then' blocks
def 'validate user - data table 1 - not working'() { when: validateUser(user) then: check() where: user || check new User(userName: 'tester') || { noExceptionThrown() } new User(userName: null) || { Exception ex = thrown(); ex.message == 'no userName' } null || { Exception ex = thrown(); ex.message == 'no user' } }
Variant 3
This one is not working because of this error raised by Spock at compile time:
Exception conditions are only allowed as top-level statements
def 'validate user - data table 2 - not working'() { when: validateUser(user) then: if (expectedException) { def ex = thrown(expectedException) ex.message == expectedMessage } else { noExceptionThrown() } where: user || expectedException | expectedMessage new User(userName: 'tester') || null | null new User(userName: null) || Exception | 'no userName' null || Exception | 'no user' }
The recommended solution is to have two methods: one that tests the good cases, and another that tests the bad cases. Then both methods can make use of data tables.
Example:
class SomeSpec extends Specification { class User { String userName } def 'validate valid user'() { when: validateUser(user) then: noExceptionThrown() where: user << [ new User(userName: 'tester'), new User(userName: 'joe')] } def 'validate invalid user'() { when: validateUser(user) then: def error = thrown(expectedException) error.message == expectedMessage where: user || expectedException | expectedMessage new User(userName: null) || Exception | 'no userName' new User(userName: '') || Exception | 'no userName' null || Exception | 'no user' } private validateUser(User user) { if (!user) throw new Exception('no user') if (!user.userName) throw new Exception('no userName') } }
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