java:如何模拟Calendar.getInstance()?

问题描述 投票:0回答:9

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

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

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

java date junit calendar mocking
9个回答
29
投票

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

在你的班级中名列前茅:

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

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

然后是嘲笑本身:

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

18
投票

据我所知,您有三个明智的选择:

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


12
投票

不要嘲笑它 - 相反,引入一个可以嘲笑的获取日期的方法。像这样的东西:

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 

}

另请参阅您应该只模拟您拥有的类型吗?测试气味 - 一切都被模拟


6
投票

使用 Mockito 和 PowerMockito:

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

请参阅链接获取完整代码。


2
投票

编写一个名为

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


1
投票

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


1
投票

与Mockk

 private lateinit var calendar: Calendar

    @Before
    fun setup() {
        calendar = mockk(relaxed = true)
        mockkStatic(Calendar::class)
        every { Calendar.getInstance() } returns calendar
    }

    @Test
    fun `test date when date is less than 16 month is 0`() {
        every { calendar[Calendar.DAY_OF_MONTH] } returns 12
        every { calendar[Calendar.MONTH] } returns 0
        every { calendar[Calendar.YEAR] } returns 2023

      // assert here

    }

请参阅mockk文档的链接


0
投票

避免使用

Calendar.getInstance()
并仅使用
Mockito
方法返回你喜欢的内容。 例如:

@Test
fun italianLocale_returnsItalianFormatDate() {
    val calendar: Calendar = Mockito.mock(Calendar::class.java)
    Mockito.`when`(calendar.get(Calendar.DAY_OF_MONTH)).thenReturn(27)
    Mockito.`when`(calendar.get(Calendar.YEAR)).thenReturn(2023)
    Mockito.`when`(calendar.get(Calendar.MONTH)).thenReturn(1)
    val formatted = calendar.toReadableDate()
    assert(formatted == "27/01/2023")
}

在你的 gradle 文件中导入 Mockito:

testImplementation ("org.mockito.kotlin:mockito-kotlin:x.x.x")

或者(如果你使用的是groovy)

testImplementation "org.mockito.kotlin:mockito-kotlin:x.x.x"

0
投票

您可以使用 Junit 5 和 Mockito 执行以下操作

@Test
public void doSomething() {
    listCalendarParams("now", Calendar.getInstance());
    Calendar fakedCalendar = new GregorianCalendar(2023, Calendar.OCTOBER, 15, 10, 15);
    listCalendarParams("mock", fakedCalendar);
    try (MockedStatic<Calendar> mockedStatic = Mockito.mockStatic(Calendar.class, Mockito.CALLS_REAL_METHODS)) {
        mockedStatic.when(Calendar::getInstance).thenReturn(fakedCalendar);
        //This or any method here using Calendar.getInstance() will be replaced by mock defined above
        Calendar calendar = Calendar.getInstance();
        listCalendarParams("evaluated", calendar);
        assertEquals(Calendar.OCTOBER, calendar.get(Calendar.MONTH));
        assertEquals(15, calendar.get(Calendar.DAY_OF_MONTH));
        assertEquals(10, calendar.get(Calendar.HOUR_OF_DAY));
        assertEquals(15, calendar.get(Calendar.MINUTE));
    }
}

private static void listCalendarParams(String nameOfCal, Calendar calendar) {
    System.out.println(nameOfCal + ":\t" +
            new SimpleDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss")
                    .format(calendar.getTime()));
}3

输出:

now:        2023-11-27T14:00:48 //This will change anytime you run it.
mock:       2023-10-15T10:15:00
evaluated:  2023-10-15T10:15:00
© www.soinside.com 2019 - 2024. All rights reserved.