操作模拟的Calendar对象以返回特定的日期

时间:2018-02-16 17:48:07

标签: junit powermock easymock

我正在使用Calendar对象来确定是否根据当前日/小时值增加系统的工作负载。鉴于此对象使用静态方法,我使用PowerMock使用以下注释模拟静态方法:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Calendar.class })

测试中的代码非常简单(虽然我的逻辑需要工作,但我知道):

public void determineDefaultMaximumScans() throws ParseException{  
parseTime();
Calendar cal = Calendar.getInstance();
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
System.out.println(cal.get(Calendar.DAY_OF_WEEK));

if(dayOfWeek == (Calendar.SATURDAY) || dayOfWeek == (Calendar.SUNDAY)){
        setDefaultMax(calculateNewDefaultMax(getDefaultMax()));
        System.out.println("defaultMax increased by 20%");
    } else {
        if(currentTime.after(afterHoursBegin) && currentTime.before(afterHoursEnd)){
            System.out.println("Not afterhours. Maintaining current maximum.");
            setDefaultMax(defaultMax);
            System.out.println("Current Maximum number of scans: " + getDefaultMax());
        }

    }
}

我的测试用例如下:

@SuppressWarnings("static-access")
@Test
public void testDetermineMaximumScans() throws ParseException{
    PowerMock.mockStatic(Calendar.class);
    String beginningTime = "18:00";
    String endingTime = "05:00";

    mockAfterHoursBegin = parser.parse(beginningTime);
    mockAfterHoursEnd = parser.parse(endingTime);
    mockCurrentTime = parser.parse(parser.format(new Date()));

    EasyMock.expect(Calendar.getInstance()).andReturn(mockCalendar);
    EasyMock.expect(mockCalendar.get(Calendar.DAY_OF_WEEK)).andReturn(6);


    EasyMock.replay(mocks);
    offHourMaximumCalculator.determineDefaultMaximumScans();
    EasyMock.verify(mocks);
}

截至目前,我所有返回特定值的尝试都会导致以下断言错误。现在我模糊地理解为什么它会返回默认值,但我不明白为什么我不能强迫价值或如何绕过这个期望。对我来说,模拟一般来说仍然是一个令人沮丧的谜。我错过了什么?

java.lang.AssertionError: 
  Expectation failure on verify:
Calendar.get(7): expected: 1, actual: 0

1 个答案:

答案 0 :(得分:1)

模拟很简单。但是想要模拟静态方法在复杂性之后是一个很大的运行。我一般不建议模仿像日历这样的东西。如果你做了奇怪而复杂的事情,只需封装一些你可以轻松测试和模拟的东西。

事实上,我们几乎从不使用Calendar.getInstance()。它根据语言环境返回一些内容。但是您很少需要特定日历,即GregorianCalendar。所以只需new GregorianCalendar

但无论如何,添加一个受保护的方法

protected Calendar newCalendar() {
    return Calendar.getInstance(); // or new GregorianCalendar()
}  

将需要2分钟,然后一个简单的部分模拟将完成这个伎俩。

最后,我也不建议使用Calendar。 Java 8中的java.util.date中有一个更好的API。

所有这些都说,这就是你应该怎么做的。 Calendar是一个系统类,因此您需要遵循一个真实的特定路径,该路径由here解释。

@RunWith(PowerMockRunner.class)
@PrepareForTest(Calendar.class)
public class MyTest {

  @Test
  public void testDetermineMaximumScans() throws ParseException {
    PowerMock.mockStatic(Calendar.class);

    Calendar calendar = mock(Calendar.class);

    EasyMock.expect(Calendar.getInstance()).andReturn(calendar);
    EasyMock.expect(calendar.get(Calendar.DAY_OF_WEEK)).andReturn(6);

    // really important to replayAll to replay the static expectation
    PowerMock.replayAll(calendar);
    assertThat(Calendar.getInstance().get(Calendar.DAY_OF_WEEK)).isEqualTo(6);

    // and verifyAll is you want to verify that the static call actually happened    
    PowerMock.verifyAll();
  }

}