【问题标题】:Manipulating a mocked Calendar object to return specific days操作模拟日历对象以返回特定日期
【发布时间】:2018-02-16 17:48:07
【问题描述】:

我正在使用日历对象来确定是否根据当前日期/小时值增加系统的工作负载。鉴于此对象使用静态方法,我使用 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

【问题讨论】:

  • 仅供参考:Calendar 是一个糟糕的老类,现在是遗留的,几年前被 java.time 类取代,例如 ZonedDateTime

标签: junit powermock easymock


【解决方案1】:

模拟相当简单。但是想要模拟静态方法是对复杂性的追求。我通常不建议模拟日历之类的东西。如果你用它做奇怪和复杂的事情,只需封装一些你可以轻松测试和模拟的东西。

事实上,我们几乎从不使用Calendar.getInstance()。它根据语言环境返回一些东西。但很少有人不想要一个特定的日历,即GregorianCalendar。所以就做new GregorianCalendar

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

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

需要 2 分钟,然后一个简单的部分模拟就可以解决问题。

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

说了这么多,这就是你应该怎么做。日历是一个系统类,所以你需要遵循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();
  }

}

【讨论】:

    猜你喜欢
    • 2015-03-03
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多