【问题标题】:java: how to mock Calendar.getInstance()?java:如何模拟 Calendar.getInstance()?
【发布时间】:2012-03-05 18:13:12
【问题描述】:

在我的代码中我有这样的东西:

private void doSomething() {
   Calendar today = Calendar.getInstance();
   ....
}

如何在我的 junit 测试中“模拟”它以返回特定日期?

【问题讨论】:

标签: java date junit calendar mocking


【解决方案1】:

您可以结合使用 PowerMock 和 Mockito 来模拟它:

在你的班级中名列前茅:

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

成功的关键是你必须把你使用 Calendar 的类放在 PrepareForTest 中,而不是 Calendar 本身,因为它是一个系统类。 (我个人在找到这个之前必须搜索很多)

然后是嘲笑本身:

mockStatic(Calendar.class);
when(Calendar.getInstance()).thenReturn(calendar);

【讨论】:

  • 您包含哪些依赖项才能使 mockStatic() 方法工作?
  • 对不起,我应该这么说。我使用 import static 来导入 PowerMockito 的 mockStatic 方法。请参阅 powermock mockito 的此依赖项:mvnrepository.com/artifact/org.powermock/powermock-api-mockito2/…
  • 你成就了我的一天!
  • +1 ,但对于第二部分,这两行都可以简化为:PowerMockito.whenNew(Calendar.getInstance()).withAnyArguments().thenReturn(MY_INSTANCE_OBJECT_TO_FEED);
【解决方案2】:

在我看来,您有三个明智的选择:

  1. 在您当天设置的任何方法/类中注入 Calendar 实例。

    private void method(final Calendar cal) { Date today = cal.getTime(); }

  2. 使用JodaTime 代替Calendar。这不是一个选项,而是一个建议,因为 JodaTime 会让你的生活更轻松。您仍然需要将这段时间注入到方法中。

    DateTime dt = new DateTime();

    Date jdkDate = dt.toDate();

  3. Calendar 包裹在一些允许您获取时间的界面中。然后,您只需模拟该接口并让它返回一个常量 Date

    Date today = calendarInterfaceInstance.getCurrentDate()

【讨论】:

  • Joda Time 的DateTimeUtils 类具有为所有其他 Joda Time 对象设置当前时间的静态方法。这对于将时间设置为某个时刻非常有用,例如用于测试。
  • @Jesper - 是的,这是真的,我忽略了一个好点
  • 谢谢你们。我听从了你的建议,然后搬到了 JodaTime。顺便说一句,它可以通过以下方式轻松解决问题: DateTimeUtils.setCurrentMillisFixed(new DateTime(2012, 2, 14, 13, 43, 21).getMillis());
【解决方案3】:

不要模拟它 - 而是引入一种可以模拟的方法来获取日期。像这样的:

interface Utility {

    Date getDate();
}

Utilities implements Utility {


    public Date getDate() {

        return Calendar.getInstance().getTime();
    }

}

然后你可以将它注入到你的类中,或者只是使用一个带有一堆静态方法的辅助类和一个接口的加载方法:

public class AppUtil {

    private static Utility util = new Utilities();

    public static void load(Utility newUtil) {

         this.util = newUtil;
    }

    public static Date getDate() {

        return util.getDate();
    }

}

然后在你的应用代码中:

private void doSomething() {
   Date today = AppUtil.getDate();
   ....
}

然后你可以在你的测试方法中加载一个模拟接口。

@Test
public void shouldDoSomethingUseful() {
     Utility mockUtility = // .. create mock here
     AppUtil.load(mockUtility);

     // .. set up your expectations

     // exercise the functionality
     classUnderTest.doSomethingViaAPI();

     // ... maybe assert something 

}

另请参阅Should you only mock types you own?Test smell - everything is mocked

【讨论】:

    【解决方案4】:

    使用 Mockito 和 PowerMockito:

    Calendar endOfMarch = Calendar.getInstance();
    endOfMarch.set(2011, Calendar.MARCH, 27);
    PowerMockito.mockStatic(Calendar.class);
    Mockito.when(Calendar.getInstance()).thenReturn(endOfMarch);
    

    完整代码请参考link

    【讨论】:

      【解决方案5】:

      使用返回Calendar.getInstance() 的方法getCalendar 编写一个名为DateHelper 的类。重构您正在测试的类,使其具有DateHelper 类型的成员变量和注入该成员变量的构造函数。在您的测试中使用该构造函数,注入 DateHelper 的模拟,其中 getCalendar 已被存根以返回某个已知日期。

      【讨论】:

        【解决方案6】:

        您可以使用 JMockit 进行模拟。在这里您可以看到如何做到这一点:Mock Java Calendar - JMockit vs Mockito

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-05-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-13
          相关资源
          最近更新 更多