英文:
PowerMockito mock gets cleared after calling real method
问题
我在使用PowerMockito对静态方法进行模拟时遇到了奇怪的行为。
注意: 2020-08-27
是执行测试时的实际系统时间。
在上面的代码示例中,您可以看到我对 LocalDate.now()
方法的所有实现以及 LocalDateTime.now()
方法的所有实现进行了模拟。我同时希望能够获得 LocalDateTime.of(LocalDate, LocalTime)
方法的真实实现。
所有的模拟在调用 LocalDateTime.of(LocalDate, LocalTime)
方法之前都能正常工作。
当我在调用了 LocalDateTime.of(LocalDate, LocalTime)
方法之后调用 LocalDateTime.now()
时,第一次获得的是真实的系统时间,而不是模拟值。但是,如果我再次调用 LocalDateTime.now()
,那么我会再次获得模拟时间。
附上了调试截图,显示了模拟结果。这是我使用的代码。
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.dom.*"})
// 这是由于Power Mock与JDK 9存在兼容性问题所需的修复(https://github.com/powermock/powermock/issues/864#issuecomment-447001997)
public class MainTest {
@Test
public void test() {
LocalDate now = LocalDate.now();
String dateString = "2020-08-24T09:00:00Z";
Instant instant = Instant.parse(dateString);
LocalDate localDate = LocalDate.ofInstant(instant, ZoneId.of("UTC"));
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.of("UTC"));
PowerMockito.mockStatic(LocalDate.class);
PowerMockito.when(LocalDate.now()).thenReturn(localDate);
PowerMockito.when(LocalDate.now(Mockito.any(ZoneId.class))).thenReturn(localDate);
PowerMockito.when(LocalDate.now(Mockito.any(Clock.class))).thenReturn(localDate);
PowerMockito.mockStatic(LocalDateTime.class);
PowerMockito.when(LocalDateTime.of(Mockito.any(LocalDate.class), Mockito.any(LocalTime.class))).thenCallRealMethod();
PowerMockito.when(LocalDateTime.now()).thenReturn(localDateTime);
PowerMockito.when(LocalDateTime.now(Mockito.any(ZoneId.class))).thenReturn(localDateTime);
PowerMockito.when(LocalDateTime.now(Mockito.any(Clock.class))).thenReturn(localDateTime);
LocalDate now1 = LocalDate.now();
LocalDateTime of = LocalDateTime.of(localDate, LocalTime.of(10, 30));
LocalDate now2 = LocalDate.now();
LocalDate now3 = LocalDate.now();
System.out.println("");
}
}
我已经花了几个小时寻找根本原因,但不幸的是还没有找到。有人能告诉我这里出了什么问题吗?
英文:
I'm experiencing a weird behaviour with PowerMockito static method mocking.
Note: 2020-08-27
is the real system time at the time of executing the test.
In the above code example as you can see I have mocked all the implementations of LocalDate.now()
method and all the implementations of LocalDateTime.now()
method. And I want the real implementation of LocalDateTime.of(LocalDate, LocalTime)
method at the same time.
All the mocks are working correctly until I call the LocalDateTime.of(LocalDate, LocalTime)
method.
When I call the LocalDateTime.now()
after calling LocalDateTime.of(LocalDate, LocalTime)
I get the real system time not the mock value for the 1st time. But if I LocalDateTime.now()
again then I again get the mocked time.
A debug screenshot is attached above with the mock results. This is the code I'm using.
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.dom.*"})
// This is needed due to a compatibility issue of Power Mock with JDK 9 (https://github.com/powermock/powermock/issues/864#issuecomment-447001997)
public class MainTest {
@Test
public void test() {
LocalDate now = LocalDate.now();
String dateString = "2020-08-24T09:00:00Z";
Instant instant = Instant.parse(dateString);
LocalDate localDate = LocalDate.ofInstant(instant, ZoneId.of("UTC"));
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.of("UTC"));
PowerMockito.mockStatic(LocalDate.class);
PowerMockito.when(LocalDate.now()).thenReturn(localDate);
PowerMockito.when(LocalDate.now(Mockito.any(ZoneId.class))).thenReturn(localDate);
PowerMockito.when(LocalDate.now(Mockito.any(Clock.class))).thenReturn(localDate);
PowerMockito.mockStatic(LocalDateTime.class);
PowerMockito.when(LocalDateTime.of(Mockito.any(LocalDate.class), Mockito.any(LocalTime.class))).thenCallRealMethod();
PowerMockito.when(LocalDateTime.now()).thenReturn(localDateTime);
PowerMockito.when(LocalDateTime.now(Mockito.any(ZoneId.class))).thenReturn(localDateTime);
PowerMockito.when(LocalDateTime.now(Mockito.any(Clock.class))).thenReturn(localDateTime);
LocalDate now1 = LocalDate.now();
LocalDateTime of = LocalDateTime.of(localDate, LocalTime.of(10, 30));
LocalDate now2 = LocalDate.now();
LocalDate now3 = LocalDate.now();
System.out.println("");
}
}
I have spent several hours looking out for the root cause but unfortunately no luck yet. Can someone please tell me what is wrong here?
答案1
得分: 1
这看起来像是 PowerMockito.mockStatic
本身的一个错误。我也在 https://github.com/powermock/powermock/issues/1066 发布了相同的问题,但我还没有收到任何回应。不过无论如何,我已经能够通过 PowerMockito.stub
方法找到了我的用例的解决方案。以下代码片段按预期工作,没有任何问题。
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.dom.*"})
// 这是由于 Power Mock 与 JDK 9 的兼容性问题所需 (https://github.com/powermock/powermock/issues/864#issuecomment-447001997)
public class MainTest {
@Test
public void test() {
LocalDate now = LocalDate.now();
String dateString = "2020-08-24T09:00:00Z";
Instant instant = Instant.parse(dateString);
LocalDate localDate = LocalDate.ofInstant(instant, ZoneId.of("UTC"));
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.of("UTC"));
PowerMockito.stub(PowerMockito.method(LocalDate.class, "now")).toReturn(localDate);
PowerMockito.stub(PowerMockito.method(LocalDate.class, "now", ZoneId.class)).toReturn(localDate);
PowerMockito.stub(PowerMockito.method(LocalDate.class, "now", Clock.class)).toReturn(localDate);
PowerMockito.stub(PowerMockito.method(LocalDateTime.class, "now")).toReturn(localDateTime);
PowerMockito.stub(PowerMockito.method(LocalDateTime.class, "now", ZoneId.class)).toReturn(localDateTime);
PowerMockito.stub(PowerMockito.method(LocalDateTime.class, "now", Clock.class)).toReturn(localDateTime);
LocalDate now1 = LocalDate.now();
LocalDateTime of = LocalDateTime.of(localDate, LocalTime.of(10, 30));
LocalDate now2 = LocalDate.now();
LocalDate now3 = LocalDate.now();
System.out.println("");
}
}
两种方法之间的区别在于,使用 PowerMockito.mockStatic
我会模拟整个类,然后使用 PowerMockito.when
定义每个方法的行为。那些没有使用 PowerMockito.when
定义的方法,如果被调用,将返回 null 或不执行任何操作。但是使用 PowerMockito.stub
,我不会模拟整个类。我仅为一组选定的方法使用 PowerMockito.stub
定义模拟行为,其他方法在被调用时将调用实际方法。
英文:
This looks like a bug with PowerMockito.mockStatic
itself. I posted the same at https://github.com/powermock/powermock/issues/1066 also. But I didn't get any response yet. Anyway, I was able to find a solution for my use case with PowerMockito.stub
method. The following code piece works as expected without any issue.
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.dom.*"})
// This is needed due to a compatibility issue of Power Mock with JDK 9 (https://github.com/powermock/powermock/issues/864#issuecomment-447001997)
public class MainTest {
@Test
public void test() {
LocalDate now = LocalDate.now();
String dateString = "2020-08-24T09:00:00Z";
Instant instant = Instant.parse(dateString);
LocalDate localDate = LocalDate.ofInstant(instant, ZoneId.of("UTC"));
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.of("UTC"));
PowerMockito.stub(PowerMockito.method(LocalDate.class, "now")).toReturn(localDate);
PowerMockito.stub(PowerMockito.method(LocalDate.class, "now", ZoneId.class)).toReturn(localDate);
PowerMockito.stub(PowerMockito.method(LocalDate.class, "now", Clock.class)).toReturn(localDate);
PowerMockito.stub(PowerMockito.method(LocalDateTime.class, "now")).toReturn(localDateTime);
PowerMockito.stub(PowerMockito.method(LocalDateTime.class, "now", ZoneId.class)).toReturn(localDateTime);
PowerMockito.stub(PowerMockito.method(LocalDateTime.class, "now", Clock.class)).toReturn(localDateTime);
LocalDate now1 = LocalDate.now();
LocalDateTime of = LocalDateTime.of(localDate, LocalTime.of(10, 30));
LocalDate now2 = LocalDate.now();
LocalDate now3 = LocalDate.now();
System.out.println("");
}
}
The difference between 2 approaches are with PowerMockito.mockStatic
I mock the whole class and then define the behaviour of each method with PowerMockito.when
. The methods which haven't been defined with PowerMockito.when
will return null or do nothing if invoked. But with PowerMockito.stub
I don't mock the whole class. I define the mocked behaviour only for a selected set of methods with PowerMockito.stub
and other methods will call the real methods if invoked.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论