[英]Mockito verify fails in second unit test
I am using Mockito together to JUnit to implement unit tests for a class in an Android project.The problem is that I call Mockito.verify
in two consequent tests where the tests are exactly same (to make sure that I am using Mockito correctly) but the interesting thing is that verify in second test always fails.I suspect that some operations need to be done before each test using @before
annotation or so, that I have missed.Here are some code snippet about what I am doing. 我将Mockito与JUnit一起使用以实现Android项目中某个类的单元测试。问题是我在两个随后的测试中调用Mockito.verify
,它们的测试完全相同(以确保我正确使用了Mockito),但是有趣的是,第二个测试中的验证总是会失败。我怀疑在每次测试之前都需要使用@before
注释或类似的东西进行一些操作,但我错过了,这里有一些我正在做的代码片段。
I use Android Studio 3.4.1, Mockito 2.7.22 and JUnit 4.12. 我使用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();
}
Here comes the function under test 测试功能到了
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();
}
}
}
I expect that both tests should pass without any problem. 我希望两项测试都可以顺利通过。 In fact, both tests are passed when I ran them individually, but they fail when I run the whole suite and the error is: 实际上,当我分别运行它们时,两个测试都通过了,但是当我运行整个套件时它们都失败了,错误是:
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.
I think the issue is a multithreading one. 我认为这个问题是多线程的。 When you call initConnection
, it calls mConnection.connect()
in a Thread
The problem you are having is that this Thread
takes some time to complete and you end up calling verify(mockedZConnection, times(1)).connect();
当您调用initConnection
,它将在Thread
调用mConnection.connect()
。您遇到的问题是该Thread
需要一些时间才能完成,最终您会调用verify(mockedZConnection, times(1)).connect();
before the Thread actually reached the connect()
call. 在线程实际到达connect()
调用之前。 A way to make sure about it is to join the Thread
after you start it, it will wait until the Thread
has finished before continuing: 确保它的一种方法是在启动Thread
后将其加入,它将等待Thread
完成后再继续:
mThread.start();
try {
mThread.join();
} catch (InterruptedException i) {
i.printStackTrace();
}
Now both tests should work. 现在,这两个测试都应该起作用。
This of course is not acceptable in the code, because it negated the use of a Thread
. 当然这在代码中是不可接受的,因为它否定了Thread
的使用。 You will need an other way to test it. 您将需要其他方式进行测试。
A way I can think of would be to wait for the Thread to complete in your test before checking the mock: 我能想到的一种方法是在测试模拟之前等待线程完成测试:
@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();
}
Tried and it works fine for me. 尝试过,对我来说很好。 Not sure it is a best practice though as you need to make public some internals of your class, which violates encapsulation 但不确定是否是最佳做法,因为您需要公开类的某些内部信息,这违反了封装
maybe having a package protected isThreadAlive()
method on your ZConnectionService
class could be acceptable 也许在您的ZConnectionService
类上使用受保护的包isThreadAlive()
方法是可以接受的
boolean isThreadAlive() {
return mThread.isAlive();
}
and the loop in the test 和测试中的循环
while(zConnectionService.isThreadAlive()) {
Thread.sleep(100);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.