在方法中多次模拟 Calendar.getInstance 静态方法
Mocking Calendar.getInstance static method multiple times in a method
我目前正在使用 JMockito/PowerMock 以便我可以模拟静态方法的 return 值,在本例中为 Calendar.getInstance()。
我的问题与此非常相似,但不完全是:
PowerMocking static does not return expected object
我还检查了其他各种类似的主题,但 none 其中的主题完全符合我的上下文。目前,我有这样的代码:
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
似乎得到了[=16=的修改版本] 之前的对象。我原以为它会得到 original 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 进行测试,但仍然遇到同样的问题。很确定这是显而易见的事情,但无法弄清楚。谢谢你的时间。
那是因为myOwn
是同一个实例。 thenReturn
代码在测试开始时仅 运行 一次。您只创建了一个 Calendar
对象,而 Mockito 只是 return 两次。因此,如果它在第一次调用 getInstance
时被修改,则修改后的对象将在第二次调用时被 returned。
试试看:
Calendar myOwn = //whatever
Calendar myOwnSecond = //whatever - new instance though, not the same as myOwn!!
when(Calendar.getInstance()).thenReturn(myOwn).thenReturn(myOwnSecond);
如果你想每次 return 一个新的日历实例(所以当你想要 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
}
});
我目前正在使用 JMockito/PowerMock 以便我可以模拟静态方法的 return 值,在本例中为 Calendar.getInstance()。 我的问题与此非常相似,但不完全是: PowerMocking static does not return expected object
我还检查了其他各种类似的主题,但 none 其中的主题完全符合我的上下文。目前,我有这样的代码:
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
似乎得到了[=16=的修改版本] 之前的对象。我原以为它会得到 original 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 进行测试,但仍然遇到同样的问题。很确定这是显而易见的事情,但无法弄清楚。谢谢你的时间。
那是因为myOwn
是同一个实例。 thenReturn
代码在测试开始时仅 运行 一次。您只创建了一个 Calendar
对象,而 Mockito 只是 return 两次。因此,如果它在第一次调用 getInstance
时被修改,则修改后的对象将在第二次调用时被 returned。
试试看:
Calendar myOwn = //whatever
Calendar myOwnSecond = //whatever - new instance though, not the same as myOwn!!
when(Calendar.getInstance()).thenReturn(myOwn).thenReturn(myOwnSecond);
如果你想每次 return 一个新的日历实例(所以当你想要 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
}
});