简体   繁体   English

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

[英]How to mock Calendar.getInstance method using JMockit?

I am trying to mock Calendar.getInstance() method using JMockit. 我试图使用JMockit模拟Calendar.getInstance()方法。 This is the first time I am mocking anything. 这是我第一次嘲笑任何东西。

Below is my method which gives me the date of either recent Monday or recent Thursday in the format of YYYYMMDD . 下面是我的方法,它以YYYYMMDD的格式给出了最近一个Monday或最近Thursday的日期。

Today is Sunday, so it should return date for Thursday in the format of YYYYMMDD so it will be - 2014027 今天是星期天,因此它应该以YYYYMMDD的格式返回星期四的日期,所以它将是 - 2014027

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

So my question is how do I mock the Calendar.getInstance method using JMokcit so that I can easily junit getCorrectDate method? 所以我的问题是我如何使用JMokcit模拟Calendar.getInstance方法,这样我可以轻松地使用junit getCorrectDate方法?

I have never mocked it before so I am facing some problem? 我以前从未嘲笑它,所以我面临一些问题?

Can anyone provide a simple example if possible on my example? 任何人都可以在我的例子中提供一个简单的例子吗?

I am trying to do it like this but it is complaining me on MockClass as it is not able to resolve.. I have added the maven dependency of JMockit as well 我试图这样做,但它在MockClass抱怨我,因为它无法解决..我已经添加了JMockit的maven依赖

@MockClass(realClass = Calendar.class) 
class CalendarMock {
 private int hour;
 private int day;
 private int minute;

 public CalendarMock(int day, int hour, int minute) {
  this.hour = hour;
  this.day = day;
  this.minute = minute;
 }

 @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;
 }
}
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;
        }
    }
 }

}

you can enhance the get logic to do stuff. 你可以增强get逻辑来做东西。

Rather than try to mock a static method here, I would strongly recommend introducing a Clock interface along these lines: 我强烈建议在这些方面引入一个Clock接口,而不是试图在这里模拟一个静态方法:

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

Then you can have a production implementation which uses new Date() or System.currentTimeMillis , and a test implementation where you can set "the current time". 然后,您可以拥有一个使用new Date()System.currentTimeMillis的生产实现,以及一个可以设置“当前时间”的测试实现。 Pass your clock to the method, or make it an instance method and "configure" the instance (eg in the constructor) with the appropriate clock. 将时钟传递给方法,或使其成为实例方法,并使用适当的时钟“配置”实例(例如,在构造函数中)。

The Clock interface makes your code much simpler to test in my experience, without having to rely on relatively advanced mocking features for mocking static methods. Clock接口使您的代码容易根据我的经验进行测试,而不必依赖相对高级的模拟功能来模拟静态方法。

So your production code would become something like: 所以你的生产代码会变成:

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
}

Now you can test that with lots of different dates and times. 现在,您可以使用许多不同的日期和时间对其进行测试。

Here is a complete test class (minus imports) for the getCorrectDate() method, using the two mocking APIs available in JMockit 1.6: 这是getCorrectDate()方法的完整测试类(减去导入),使用JMockit 1.6中提供的两个getCorrectDate() 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();
    }
}

I would say both tests are quite simple, without having to change the original production code. 我想说两个测试都非常简单,无需更改原始生产代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM