我正在一起使用Mockito和JUnit来为Android项目中的类实现单元测试。问题是我在两个随后的测试中调用了Mockito.verify
,这些测试完全相同(以确保我是正确使用Mockito),但有趣的是第二次测试中的验证始终会失败。我怀疑每次使用@before
批注进行测试之前都需要做一些操作,而我已经错过了。以下是一些代码段我在做什么。
我使用Android Studio 3.4.1,Mockito 2.7.22和JUnit 4.12。
@Test
public void test_onStart_do_nothing() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
verify(mockedZConnection, times(1)).connect();
}
@Test
public void test_onStart_throw_IO_exceptioon() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
// Line above is the line that error message points to!
verify(mockedZConnection, times(1)).connect();
}
正在测试的功能
public void initConnection(ZConnection connection) {
Log.d(TAG,"initConnection()");
if (mConnection == null) {
mConnection = connection;
}
if (!mActive) {
mActive = true;
if (mThread == null || !mThread.isAlive()) {
mThread = new Thread(new Runnable() {
@Override
public void run() {
// The code here runs in a background thread.
Looper.prepare();
mTHandler = new Handler();
try {
mConnection.connect();
} catch (IOException e) {
Intent i = null;
i = new Intent(ZConnectionService.UI_NOTCONNECTED);
i.setPackage(getApplicationContext().getPackageName());
getApplicationContext().sendBroadcast(i);
e.printStackTrace();
// Stop the services all together.
stopSelf();
}
Looper.loop();
}
});
mThread.start();
}
}
}
我希望两项测试都可以顺利通过。实际上,当我分别运行它们时,两个测试都通过了,但是当我运行整个套件时它们都失败了,错误是:
Wanted but not invoked:
mockedZinkConnection.connect();
-> at com.app.z.ZConnectionServiceUnitTest.test_onStart_throw_IO_exceptioon(ZConnectionServiceUnitTest.java:207)
Actually, there were zero interactions with this mock.
答案 0 :(得分:1)
我认为这个问题是多线程的。
当您呼叫initConnection
时,它会在mConnection.connect()
中呼叫Thread
您遇到的问题是,此Thread
需要花费一些时间才能完成,并且最终您会在线程实际到达verify(mockedZConnection, times(1)).connect();
调用之前调用connect()
。
确保它的一种方法是在启动Thread
之后加入它,它会等到Thread
完成后再继续:
mThread.start();
try {
mThread.join();
} catch (InterruptedException i) {
i.printStackTrace();
}
现在两个测试都应该可以工作。
这在代码中当然是不可接受的,因为它否定了Thread
的使用。您将需要另一种方法进行测试。
我能想到的一种方法是在测试模拟之前等待线程完成:
@Test
public void test_onStart_throw_IO_exceptioon() throws Exception {
ZConnectionService zConnectionService = new ZConnectionService();
ZConnection mockedZConnection = mock(ZConnection.class);
doNothing().when(mockedZConnection).connect();
zConnectionService.initConnection(mockedZConnection);
// Wait for the Thread to complete
while(zConnectionService.mThread.isAlive()) {
Thread.sleep(100);
}
verify(mockedZConnection, times(1)).connect();
}
尝试过,对我来说很好。但是,由于您需要公开类的某些内部结构(违反封装
),因此不确定是否是最佳做法在您的isThreadAlive()
类上使用受软件包保护的ZConnectionService
方法是可以接受的
boolean isThreadAlive() {
return mThread.isAlive();
}
和测试中的循环
while(zConnectionService.isThreadAlive()) {
Thread.sleep(100);
}