DEV Community

Nancy Deschenes
Nancy Deschenes

Posted on

2 3

Grails: Mocking domain objects/criteria that reference Joda Time objects

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))
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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()
  }
}
Enter fullscreen mode Exit fullscreen mode

What happens? well....

java.lang.IllegalArgumentException: Property [memberSince] is not a valid property of class [com.mycompany.Membership]
Enter fullscreen mode Exit fullscreen mode

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)
  }

  // [...]
}    
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more