我将 Mockito 与 JUnit 一起使用来为 Android 项目中的类实现单元测试。问题是我在两个后续测试中调用 Mockito.verify
,其中测试完全相同(到确保我正确使用 Mockito),但有趣的是,第二次测试中的验证总是失败。我怀疑在每次测试之前需要使用 @before
注释完成一些操作,所以我错过了。这里有一些关于我正在做的事情的代码 fragment 。
我使用 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.
最佳答案
我认为问题是多线程问题。
当您调用 initConnection
时,它会在 Thread
中调用 mConnection.connect()
您遇到的问题是这个Thread
需要一些时间才能完成,并且您最终在线程之前调用verify(mockedZConnection, times(1)).connect();
实际上到达了 connect()
调用。
确保这一点的一种方法是在启动Thread
后加入它,它将等到Thread
完成后再继续:
mThread.start();
try {
mThread.join();
} catch (InterruptedException i) {
i.printStackTrace();
}
现在两个测试都应该可以工作。
这在代码中当然是 Not Acceptable ,因为它否定了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();
}
试过了,对我来说效果很好。不确定这是最佳实践,因为您需要公开类的一些内部结构,这违反了封装
也许您的 ZConnectionService
类上有一个受包保护的 isThreadAlive()
方法是可以接受的
boolean isThreadAlive() {
return mThread.isAlive();
}
以及测试中的循环
while(zConnectionService.isThreadAlive()) {
Thread.sleep(100);
}
关于java - Mockito 验证在第二个单元测试中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56390990/