无法模拟 Executors.newSingleThreadExecutor() 并调用真正的方法
Cannot mock Executors.newSingleThreadExecutor() and the real method is called
我正在尝试为此方法编写单元测试:
public class ClassToTest{
....
public void execute() {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(this::launch);
}
....
}
并且我尝试模拟 Executors.newSingleThreadExecutor() 使 executorService 与我的测试在同一线程上运行,以便我的断言发生在 executorService 执行之后而不是之前:
@RunWith(PowerMockRunner.class)
@PrepareForTest({
AnOtherClass.class,
Executors.class
})
public class TestClass {
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(Executors.class);
ExecutorService executorService = mock(ExecutorService.class);
implementAsDirectExecutor(executorService);
PowerMockito.when(Executors.newSingleThreadExecutor()).thenReturn(executorService);
}
private void implementAsDirectExecutor(ExecutorService executor) {
doAnswer(invocation -> {
Object[] args = invocation.getArguments();
Runnable runnable = (Runnable)args[0];
runnable.run();
return null;
}).when(executor).submit(any(Runnable.class));
}
@Test
public void testMethod() {
....
classToTest.execute();
.... //assert something
}
}
问题:
即使 PowerMockito.when(Executors.newSingleThreadExecutor()).thenReturn(executorService);
调用了真正的方法,但我没有得到模拟的 ExecutorService。
解决方案 1
这个问题也可以通过将 ClassToTest
添加到 @PrepareForTest
来解决。
@PrepareForTest({
AnOtherClass.class,
Executors.class,
ClassToTest.class
})
解决方案 2
但我更喜欢@Andy的解决方案,它更干净:
我在 ClassToTest
的构造函数中传递了我的 ExecutorService,就这样,我摆脱了 PowerMock:
public class ClassToTest{
....
public ClassToTest(ExecutorService executorService) {
....
}
....
public void execute() {
executorService.submit(this::launch);
}
....
}
另一种思考方式是将 ExecutorService
注入 test-class 以进行测试:
public class ClassToTest {
private ExecutorService testExecutor;
...
public void execute() {
ExecutorService executor;
if (testExecutor == null) {
executor = Executors.newSingleThreadExecutor();
} else {
executor = testExecutor;
}
executor.submit(this::launch);
}
...
public void setTestExecutor(ExecutorService testExecutor) {
this.testExecutor = testExecutor;
}
}
然后您可以使用 PowerMockito 的更多标准接口模拟,而不是覆盖静态 classes。
我正在尝试为此方法编写单元测试:
public class ClassToTest{
....
public void execute() {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(this::launch);
}
....
}
并且我尝试模拟 Executors.newSingleThreadExecutor() 使 executorService 与我的测试在同一线程上运行,以便我的断言发生在 executorService 执行之后而不是之前:
@RunWith(PowerMockRunner.class)
@PrepareForTest({
AnOtherClass.class,
Executors.class
})
public class TestClass {
@Before
public void setUp() throws Exception {
PowerMockito.mockStatic(Executors.class);
ExecutorService executorService = mock(ExecutorService.class);
implementAsDirectExecutor(executorService);
PowerMockito.when(Executors.newSingleThreadExecutor()).thenReturn(executorService);
}
private void implementAsDirectExecutor(ExecutorService executor) {
doAnswer(invocation -> {
Object[] args = invocation.getArguments();
Runnable runnable = (Runnable)args[0];
runnable.run();
return null;
}).when(executor).submit(any(Runnable.class));
}
@Test
public void testMethod() {
....
classToTest.execute();
.... //assert something
}
}
问题:
即使 PowerMockito.when(Executors.newSingleThreadExecutor()).thenReturn(executorService);
调用了真正的方法,但我没有得到模拟的 ExecutorService。
解决方案 1
这个问题也可以通过将 ClassToTest
添加到 @PrepareForTest
来解决。
@PrepareForTest({
AnOtherClass.class,
Executors.class,
ClassToTest.class
})
解决方案 2
但我更喜欢@Andy的解决方案,它更干净:
我在 ClassToTest
的构造函数中传递了我的 ExecutorService,就这样,我摆脱了 PowerMock:
public class ClassToTest{
....
public ClassToTest(ExecutorService executorService) {
....
}
....
public void execute() {
executorService.submit(this::launch);
}
....
}
另一种思考方式是将 ExecutorService
注入 test-class 以进行测试:
public class ClassToTest {
private ExecutorService testExecutor;
...
public void execute() {
ExecutorService executor;
if (testExecutor == null) {
executor = Executors.newSingleThreadExecutor();
} else {
executor = testExecutor;
}
executor.submit(this::launch);
}
...
public void setTestExecutor(ExecutorService testExecutor) {
this.testExecutor = testExecutor;
}
}
然后您可以使用 PowerMockito 的更多标准接口模拟,而不是覆盖静态 classes。