【发布时间】:2016-11-17 15:12:37
【问题描述】:
假设我有一个具有以下构造函数的类:
public class MyImpl extends Abstract<Foo> {
@Autowired
private FooClass foo;
private final ThreadPoolExecutor executor;
public MyImpl(String name, int num) {
super(name);
this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(num);
}
这个类有以下方法:
@Override
public void doThis() {
for (int i = 0; i < num; i++) {
executor.execute(() -> foo.doMethod());
}
executor.shutdown();
super.doThis();
}
现在,我想测试 foo.doMethod 是否被调用了 4 次和 executor.execute(any()) 和 executor.shutdown() 也被调用了 4 次。
目前为止
@RunWith(PowerMockRunner.class)
@PrepareForTest(Executors.class)
public class MyImplTest {
private static final int NUM = 4;
@Mock
private FooClass foo;
@Mock
private ThreadPoolExecutor executor;
@InjectMocks
private MyImpl imyImpl = new MyImpl("Name", NUM);
@Test
public void shouldCallFourTimes() throws Exception {
PowerMockito.mockStatic(Executors.class);
when(Executors.newFixedThreadPool(NUM)).thenReturn(foo);
myImpl.doThis();
PowerMockito.verifyStatic();
Executors.newFixedThreadPool(NUM);
verify(foo, times(NUM)).doMethod());
}
但是这不起作用。 Mockito 说我的模拟执行器没有任何交互。
由于@Autowired 依赖不是构造函数的一部分,我需要在字段中使用@InjectMocks 指定构造函数。然而,到了我PowerMockito.mockStatic(Executors.class)的时候,MyImpl的构造函数已经通过一个“真实的”Executors.newFixedThreadPool创建了自己的执行器。
知道如何解决这个问题吗?
更新: 显然改变设计没什么大不了的,我现在有以下内容:
public class MyImpl extends Abstract<Foo> {
@Autowired
private FooClass foo;
private final ThreadPoolExecutor executor;
public MyImpl(String name, ThreadPoolExecutor executor) {
super(name);
this.executor = executor;
}
测试:
@Mock
private ThreadPoolExecutor executor;
@InjectMocks
private MyImpl imyImpl = new MyImpl("Name", executor);
但是,executor 在到达构造函数时以某种方式为空。
【问题讨论】:
-
你不应该用 'new MyImpl("Name", NUM)' 创建新对象,@InjectMocks 会自动实例化一个
-
如果我不这样做,Mockito 会抱怨 MyImpl 没有默认构造函数。注意
FooClass foo没有作为参数传递给构造函数 -
一些解释将如何得到极大的赞赏
-
您已经得到了答案(我会建议与 SpaceTrucker 相同)。不管怎样,你可能想看看这些视频来提高你编写可测试代码的技能:youtube.com/playlist?list=PLD0011D00849E1B79
标签: java spring unit-testing mockito powermock