在方法

时间:2016-01-08 17:02:41

标签: java unit-testing calendar powermockito

我目前正在使用JMockito / PowerMock,以便我可以模拟静态方法的返回值,在本例中为Calendar.getInstance()。 我的问题与此非常相似,但并不完全如此: PowerMocking static does not return expected object

我还检查了其他各种类似的主题,但没有一个完全属于我的背景。目前,我有一个像这样的代码:

Calendar cal = Calendar.getInstance();
//modifies this instance
.....
.....
//then there is another call:
cal2 = Calendar.getInstance();
....
....

逻辑的作用在这里并不重要。当我尝试测试这个方法块时,我的期望是这样的:

Calendar myOwn = //whatever
when(Calendar.getInstance()).thenReturn(myOwn);

因此在测试期间测试的结果是,在Calendar.getInstance()的第一次调用中,它设法成功获得myOwn对象,这正是我所期望的。显然,该方法然后对此对象进行了一些修改。

然而,在调试时,当下一次调用Calendar.getInstance()发生时,变量cal2似乎从之前获得myOwn对象的修改版本。我原本以为它会获得原始的 myOwn日历对象,但它没有。

我也尝试重建对此的期望(因为总共有两个getInstance()调用,至少在此方法中):

when(Calendar.getInstance()).thenReturn(myOwn).theReturn(myOwn);

但没有运气。然后我想是否这是一个变量通过引用传递的问题,因为它是静态的,但是,以下输出是有效的,并且完全合乎逻辑,因为我单独测试它。

Calendar cal = Calendar.getInstance();
System.out.println(cal.getTime()); //prints current date object (as expected)

cal.set(Calendar.YEAR, 2017);
System.out.println(cal.getTime()); //prints modified timestamp of 2017 (as expected)

//new instance
Calendar cal2 = Calendar.getInstance();
System.out.println(cal2.getTime()); //still prints current date object (as expected)

如果我在修改之前克隆了之前代码中的第二个日历对象实例,我可以轻松修复我的测试。但这涉及修改现有的源代码,因为它是一个非常遗留的代码。

那么在我使用这种静态方法进行单元测试时,我做错了什么?我也试过用JMockit进行测试,但仍然遇到同样的问题。很确定它是显而易见的东西,但无法弄清楚。谢谢你的时间。

1 个答案:

答案 0 :(得分:1)

那是因为myOwn是同一个实例。 thenReturn代码仅在测试开始时运行一次。您只创建了一个Calendar对象,而Mockito只是将其返回两次。因此,如果在第一次调用getInstance时对其进行了修改,则该修改后的对象将在第二次被调用时返回。

尝试改为:

Calendar myOwn = //whatever
Calendar myOwnSecond = //whatever - new instance though, not the same as myOwn!!
when(Calendar.getInstance()).thenReturn(myOwn).thenReturn(myOwnSecond);

如果您希望每次都返回一个新的日历实例(因此,当您需要x个日历实例数时),并且您不需要为测试保留日历实例,您将要使用thenAnswer。查看here了解详细信息。或者只使用:

when(Calendar.getInstance()).thenAnswer((invocation)->new MyCalendar());

或Java 7

when(Calendar.getInstance())
    .thenAnswer(new Answer<Calendar>() {
        Calendar answer(InvocationOnMock invocation) {
            return // however you're instantiating it
    }
});