Anton Hlinisty Anton Hlinisty - 1 month ago 11
Groovy Question

Spock validation issues for integration tests in grails project

I'm a newbie in unit/integration/functional testing. I use Spock for my integration tests in Grails 3.1.7 and face several problems.

1) I use @grails.transaction.Rollback annotation for my test spec but it doesn't clean the database from entries that are referenced and they are accessible from other specs (test classes). For example an instance of User domain class because it is used by springSecurityService for authentication (the tested services retrieve the logged in user from Spring Security). It's a bit annoying but not critical, nevertheless may be someone encountered the same problem and has a solution? SecurityContextHolder.clearContext() in cleanup() didn't help, only retrieving list()s using GORM and deleting manually.

2) The major problem is that I have a custom validator for my domain classes that work both for started app and in grails console, but not during the tests running.

I have 2 similar validators for 2 domain classes, one of them passes and another one - doesn't.

The main idea of this validation is that User may have 2 emails. One for logging in and another to show in profile. User can't choose another user's email to be shown in profile (and the opposite).

The one that passes the corresponding test (applied to email in User domain class):

validator: {email, user ->
UserProfile userProfile = UserProfile.findByProfileEmail(email)

if (!userProfile) {
true
} else if (userProfile?.user == user) {
true
} else {
false
}
}


Another one is the same but User is checked for profile email (applied to profileEmail in UserProfile domain class):

validator: {profileEmail, userProfile ->
User user = User.findByEmail(profileEmail)

if (!user) {
true
} else if (user?.userProfile == userProfile){
true
} else {
false
}
}


A code sample from test:

def setup() {
userService.createUser(email: EMAIL, password: PASSWORD, firstName: FIRST_NAME)
springSecurityService.reauthenticate(EMAIL, PASSWORD)
}

void "Attempt to set non-unique profileEmail"() {
given: "Create additional user"
userService.createUser(email: EMAIL_ADDITIONAL, password: PASSWORD, firstName: FIRST_NAME)

when: "Set user's profile email the same as additional user's email"
userProfileService.updateUserProfile([profileEmail: EMAIL_ADDITIONAL])

then: "Check that non-unique profileEmail was not saved"
User.findByEmail(EMAIL).userProfile.profileEmail != EMAIL_ADDITIONAL
}


Somehow my custom validator works for console and running app but does not work for integration testing.

May be more code samples from services or domain classes are needed? Will the link to github repo help?

Answer

The problem was caused by inproper interaction between the mocked dependent domain objects. In my case UserProfile belongs to User, and if you change the UserProfile but then retrieve it from the User - you're going to get a surprise (validation will not work).

Some info may be found right here: Unit test grails with domain objects using GORM functions