Unit testing 使用Mockito对调用异步函数的函数进行单元测试
我有一个调用异步函数的方法:Unit testing 使用Mockito对调用异步函数的函数进行单元测试,unit-testing,junit,mockito,Unit Testing,Junit,Mockito,我有一个调用异步函数的方法: public class MyService { ... public void uploadData() { MyPool.getInstance().getThreadPool().execute(new Runnable() { @Override public void run() { boolean suc = upload();
public class MyService {
...
public void uploadData() {
MyPool.getInstance().getThreadPool().execute(new Runnable() {
@Override
public void run() {
boolean suc = upload();
}
});
}
}
我想用以下方法对该函数进行单元测试:
MyPool mockMyPool = Mockito.mock(MyPool.class);
ThreadPool mockThreadPool = Mockito.mock(ThreadPool.class);
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
when(mockMyPool.getThreadPool()).thenReturn(mockThreadPool);
MyService service = new MyService();
// run the method under test
service.uploadData();
// set the runnableCaptor to hold your callback
verify(mockThreadPool).execute(runnableCaptor.capture());
MyPool mockMyPool=Mockito.mock(MyPool.class);
ThreadPool mockThreadPool=Mockito.mock(ThreadPool.class);
ArgumentCaptor runnableCaptor=ArgumentCaptor.forClass(Runnable.class);
当(mockMyPool.getThreadPool())。然后返回(mockThreadPool);
MyService service=newmyservice();
//运行测试中的方法
service.uploadData();
//设置runnableCaptor以保持回调
验证(mockThreadPool).execute(runnableCaptor.capture());
但我有一个错误:
org.mockito.exceptions.verification.WantedButNotInvoked:
Wanted but not invoked:
threadPool.execute(
<Capturing argument>
);
org.mockito.exceptions.verification.wantedbutnotcalled:
需要但未调用:
threadPool.execute(
);
为什么会出现这个错误,如何用Mockito对uploadData()函数进行单元测试?好的,我自己想出了一个方法,因为
MyPool
是一个单例。我添加了一个公共函数setInstance(mockedInstance)
来将模拟的实例传递给MyPool
。然后,它起作用了。我知道这有点“脏”,但如果你有更好的解决方案,请让我知道。谢谢 除了您发现的保留MyPool或ThreadPool字段的DI方法外,您还可以稍微进行重构,以允许在方法中注入依赖项:
这可能更干净,因为它将您的线程池降低到您需要的抽象级别(Executor),这意味着您只模拟了一个方法接口,而不是线程池(我假设它与ThreadPoolService相关;否则,您也可以接受线程池)。您的uploadData()
将不会经过正式测试,但您可以轻松彻底地测试uploadData(Executor)
或uploadData(ThreadPool)
,它们是最有可能断裂的运动部件
包私有技巧依赖于代码和测试在同一个包中,尽管它们可能在不同的源文件夹中;或者,您可以将ThreadPool接收调用作为公共API的一部分,这将允许以后更加灵活。MyPool.getInstance()如何知道您的
mockMyPool
并将其返回?使用而不是单例。
public class MyService {
...
public void uploadData() {
uploadData(MyPool.getInstance().getThreadPool());
}
/** Receives an Executor for execution. Package-private for testing. */
void uploadData(Executor executor) {
executor.execute(new Runnable() {
@Override public void run() {
boolean suc = upload();
}
});
}
}