如何使用JMockit模拟Calendar.getInstance方法?

时间:2014-03-02 16:57:18

标签: java junit mocking jmockit

我正在尝试使用JMockit模拟Calendar.getInstance()方法。这是我第一次嘲笑任何东西。

以下是我的方法,它以Monday的格式向我提供最近Thursday或最近YYYYMMDD的日期。

今天是星期日,因此它应该以{{1​​}}的格式返回星期四的日期,因此它将是 - YYYYMMDD

2014027

所以我的问题是如何使用JMokcit模拟public static String getCorrectDate() { Calendar cal = Calendar.getInstance(); try { int dow = cal.get(Calendar.DAY_OF_WEEK); switch (dow) { case Calendar.THURSDAY: case Calendar.FRIDAY: case Calendar.SATURDAY: case Calendar.SUNDAY: while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.THURSDAY) { cal.add(Calendar.DATE, -1); } break; case Calendar.MONDAY: case Calendar.TUESDAY: case Calendar.WEDNESDAY: while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { cal.add(Calendar.DATE, -1); } break; } } catch (Exception ex) { // log error } return toDateFormat.format(cal.getTime()); } 方法,以便我可以轻松地使用Calendar.getInstance方法?

我以前从未嘲笑它,所以我遇到了一些问题?

在我的例子中,任何人都可以提供一个简单的例子吗?

我试图这样做,但它在getCorrectDate抱怨我,因为它无法解决..我已经添加了JMockit的maven依赖

MockClass

3 个答案:

答案 0 :(得分:3)

public class CalendarTest {

    @Test
    public void testCalender() {

        new MockCalendar(1,2,3);

        Calendar c = Calendar.getInstance();
        int day = c.get(Calendar.HOUR_OF_DAY);
        Assert.assertEquals(day, 2);
    }

  public static class MockCalendar extends MockUp<Calendar> {
        private int hour;
        private int minute;
        private int day;

        public MockCalendar(int day, int hour, int minute) {
            this.hour = hour;
            this.minute = minute;
            this.day = day;
        }
        @Mock
        protected void $init() {}

        @Mock
        public static Calendar getInstance() {
            return new GregorianCalendar(1970,1,1);
        }

        @Mock
        public int get(int id) {
            if (id == Calendar.HOUR_OF_DAY) {
                return hour;
            }
            if (id == Calendar.DAY_OF_WEEK) {
                return day;
            }

            if (id == Calendar.MINUTE) {
                return minute;
            }
            return -1;
        }
    }
 }

}

你可以增强获取逻辑来做事。

答案 1 :(得分:1)

我强烈建议在这些行中引入Clock接口,而不是尝试在此处模拟静态方法:

public interface Clock {
    Date now(); // Or long, or Instant if you're using Joda Time
}

然后,您可以拥有一个使用new Date()System.currentTimeMillis的生产实现,以及一个可以设置“当前时间”的测试实现。将时钟传递给方法,或使其成为实例方法,并使用适当的时钟“配置”实例(例如在构造函数中)。

根据我的经验,Clock界面使您的代码更多更容易测试,而不必依赖相对高级的模拟功能来模拟静态方法。

因此,您的生产代码将变为:

public static String getCorrectDate(Clock clock) {
    Calendar cal = new GregorianCalendar();
    cal.setTimeZone(...); // Which time zone are you interested in?
    cal.setTime(clock.now()); // Or cal.setTimeInMillis(clock.now());

    // ... logic as before
}

现在你可以用很多不同的日期和时间来测试它。

答案 2 :(得分:0)

这是getCorrectDate()方法的完整测试类(减去导入),使用JMockit 1.6中提供的两个模拟API:

public class DateAdjustmentTest
{
    final int year = 2014;
    final int month = Calendar.MARCH;
    final Calendar[] datesOnDifferentWeekdays = {
        new GregorianCalendar(year, month, 2), // a sunday
        new GregorianCalendar(year, month, 3), // a monday
        new GregorianCalendar(year, month, 4), // a tuesday
        new GregorianCalendar(year, month, 5), // a wednesday
        new GregorianCalendar(year, month, 6), // a thursday
        new GregorianCalendar(year, month, 7), // a friday
        new GregorianCalendar(year, month, 8), // a saturday
    };

    @Test
    public void getAdjustedDateAccordingToWeekday_usingExpectationsAPI()
    {
        new NonStrictExpectations(Calendar.class) {{
            // Each consecutive call to this method will return the next date.
            // Calls to other Calendar methods will not be mocked.
            Calendar.getInstance(); result = datesOnDifferentWeekdays;
        }};

        assertEachDayOfWeekGetsCorrectlyAdjusted();
    }

    void assertEachDayOfWeekGetsCorrectlyAdjusted()
    {
        String thursdayOfPreviousWeek = "27/02/2014";
        assertEquals(thursdayOfPreviousWeek, getCorrectDate());

        String mondayOfSameWeek = "03/03/2014";
        assertEquals(mondayOfSameWeek, getCorrectDate());
        assertEquals(mondayOfSameWeek, getCorrectDate());
        assertEquals(mondayOfSameWeek, getCorrectDate());

        String thursdayOfSameWeek = "06/03/2014";
        assertEquals(thursdayOfSameWeek, getCorrectDate());
        assertEquals(thursdayOfSameWeek, getCorrectDate());
        assertEquals(thursdayOfSameWeek, getCorrectDate());
    }

    @Test
    public void getAdjustedDateAccordingToWeekday_usingMockUpAPI()
    {
        new MockUp<Calendar>() {
            @Mock
            Calendar getInstance(Invocation inv)
            {
                return datesOnDifferentWeekdays[inv.getInvocationIndex()];
            }
        };

        assertEachDayOfWeekGetsCorrectlyAdjusted();
    }
}

我想说两个测试都非常简单,无需更改原始生产代码。