Grails: Mocking domain objects/criteria that reference Joda Time objects
Nancy Deschenes
Posted on July 11, 2018
I can rant about the difficulties of handling time correctly when programming like anyone else who has ever tried. I can also criticize the default date and time objects in Java, but I will just say this: Just use Joda Time. You can also take a peek at an article I wrote a while back for more details. I even use Joda Time in my domain objects in Grails. It requires a small amount of configuration, but it is well worth it. See the plugin for more details.
Where things get a bit more complicated is when I want to test my GORM criteria when the criteria involves an org.joda.time.DateTime
. For example:
/** My domain object */
class Membership {
User user
DateTime memberSince
}
/** My service */
class MembershipService {
boolean transactional = true
/** Return users who have been around for at least 5 years */
List<User> findOldUsers() {
Membership.createCriteria().list() {
user {
eq('deleted', false)
}
lte('memberSince', new DateTime().minusYears(5))
}
}
}
Now, the test:
@Mock([Membership, User])
@TestFor(MembershipService)
class MembershipServiceSpec extends Specification {
def "findOldUsers does not return anything if all the users have been around less than a year"() {
given:
User u1 = new User().save()
// or save(false) if there are constraints we want to ignore for the time being)
new Membership(user: user, memberSince: new DateTime().minusMonths(4)).save();
expect:
service.findOldUsers().isEmpty()
}
}
What happens? well....
java.lang.IllegalArgumentException: Property [memberSince] is not a valid property of class [com.mycompany.Membership]
Of course, the GORM mocking framework doesn't know about DateTime, so it didn't register it as a property of Membership. To fix this, all we need to do is, first tell the mocking framework about Joda Time classes, and second, we have to mock our domain objects after we mock the Joda Time classes.
import grails.plugin.jodatime.simpledatastore.SimpleMapJodaTimeMarshaller
@Mock(User)
@TestFor(MembershipService)
class MembershipServiceSpec extends Specification {
setup() {
SimpleMapJodaTimeMarshaller.initialize()
mockDomain(Membership)
}
// [...]
}
Posted on July 11, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.