Sometime ago at work I needed to unit-test a Groovy class that was using java.util.Calendar in method-local scope. The SUT (system under test) was similar to the following DateUtils class:

class DateUtils {
    static def isTodayMonday() {
        Calendar now = Calendar.getInstance()
        int currentDayOfWeek = now.get(Calendar.DAY_OF_WEEK)
        return Calendar.MONDAY == currentDayOfWeek
    }
}

In order to unit-test DateUtils.isTodayMonday(), we need two test cases:

  1. A test case that demonstrates that isTodayMonday() returns true if java.util.Calendar returns Calendar.MONDAY as the current day of week, and
  2. A test case that demonstrates that isTodayMonday() returns false if java.util.Calendar returns anything other than Calendar.MONDAY as the current day of week.

As you know, it is not easy to stub Calendar.getInstance() and Calendar.get(int) in Java when they are used like this. However in Groovy maps can be coerced into classes at runtime and this simplifies writing our unit test:

@Test
void isTodayMondayShouldReturnTrueIfTodayIsMonday() {
    // Create a calendar stub that always returns MONDAY for the current day of week
    def stubCalendar = [get: { int field -> Calendar.MONDAY}] as Calendar;

    // Override Calendar.getInstance() so that it always returns our calendar stub
    Calendar.metaClass.static.getInstance = { stubCalendar }

    assert DateUtils.isTodayMonday()
}

@Test
void isTodayMondayShouldReturnFalseIfTodayIsNotMonday() {
    // Create a calendar stub that does not return MONDAY, (e.g. returns TUESDAY) for the current day of week
    def stubCalendar = [get: { int field -> Calendar.TUESDAY}] as Calendar;

    // Override Calendar.getInstance() so that it always returns our calendar stub
    Calendar.metaClass.static.getInstance = { stubCalendar }

    assert DateUtils.isTodayMonday() == false
}

In a later post I’ll explain why I prefer this approach over using Grails’ built-in StubFor.

Note: I have simplified this unit test by not testing for all days of the week. Otherwise in a more rigorous test suite, one would probably write one test case per each day of the week.