I'm attempting to do some simple mocking of a Domain class within a unit test for a Grails service as per following the documentation, but it does not seem to be working at all, in that queries for instances always return null. Am I missing something simple? Here is the relevant part of my code, I altered class and test method names for clarity:
@TestFor(MyService)
@TestMixin(DomainClassUnitTestMixin)
class MyServiceTests {
void testMyThing() {
defineBeans {anotherService(AnotherService)} //My service under test uses another service, unlikely relevant?
MyUser.metaClass.isDirty = { //workaround for mockDomain not adding isDirty method.
println("dirty check called");
}
mockDomain(MyUser, [
[username: "[email protected]", accountType: UserType.STANDARD, id: 1L],
[username: "[email protected]", accountType: UserType.STANDARD, id:3L],
[username: "[email protected]", accountType: UserType.BUSINESS, id:2L]
])
MyUser user1 = MyUser.get(1);
System.out.println("user 1: ${user1}"); // output is 'user 1: null'
MyUser user1byName = MyUser.findByUsername("[email protected]");
System.out.println("user 1 by name: ${user1byName}"); // output is 'user 1 by name: null'
... the actual testing stuff which would love to have non null MyUser objects ...
}
}
I figured it out, and you'd think I would have thought of this given I've been previously bitten by it. The problem was with validation, and Grails' default GORM behaviour of silently failing to persist data on save() (which mockDomain must use when you pass it data for your mock instances) if the Domain class has validation errors. MyUser required a non blank password.
Long ago I added grails.gorm.failOnError=true
to my Config.groovy for my application so I never think about it anymore, but of course that doesn't get read in for unit tests
In my opinion this makes that signature of mockDomain very fragile (and I couldn't find a way of setting failOnError=true). I switched the mock data setup to the following, which has the exact same result, but gives immediate failure if you set up your data incorrectly.
@Mock(MyUser)
class MyServiceTests {
...
void testMyThing() {
new MyUser(username: "[email protected]",
accountType: UserType.STANDARD,
id: 1L).save(failOnError:true) //throws exception because MyUser requires password field to be non blank
...
}
}
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