但是,测试的方法中如果存在线程的调用来执行录制行为,很多情况用Expectations{}块测试都不会通过,而使用NonStrictExpectations{}块来录制就不会有问题。
示例:
测试目标:
package ;
import ;
import ;
class OtherVO {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
= value;
}
}
public class Work {
private OtherVO otherVO;
private ExecutorService executor = (4);
public void task() {
(new Runnable() {
public void run() {
();
}
});
}
}
测试文件:
package ;
import ;
import ;
import ;
import ;
import .;
import ;
import ;
@RunWith()
public class WorkTest {
@Tested
@Mocked
Work work;
@Test
public void testTask() {
final OtherVO otherVO = new OtherVO();
new Expectations() { // mock OtherVO的行为
{
();
result = "zero";
}
};
new Expectations() {
{
(work, "otherVO", otherVO);
}
};
// --- 通过以上方式可以将mock出来的otherVO设置到work中,当然可以采取其它简便方式
();
}
}
运行测试,会发现测试不通过,会抛出一下异常:
: Missing 1 invocation to:
#getValue()
on mock instance: @3419866c
at ..(:50)
at (:38)
at (:459)
at (:675)
at (:382)
at (:192)
Caused by: Missing invocations
at ()
at $1.<init>(:23)
at (:21)
at .invoke0(Native Method)
at (:497)
... 6 more
明明调用了(),task()里会调用getValue()方法,但是怎么会报Missing invocations错误(少调了OtherVO#getValue()方法)。为什么呢?原因在于线程的调用,()只是通知线程去执行runnable,runnable中任务的执行需要JVM去调度,至于什么时候去执行,可能发生在整个testTask()结束后,而Expectations{}检测到录制行为在testTask()结束前依然没被回放,因此就会报错。
怎么解决呢?
在()调用后sleep()一段时间,以等runnable中任务被执行了再结束testTask()不就可以了么。这也是一个办法。但最好的解决方式是mock executor的execute()方法,让它不执行(),而是执行(),如下:
@RunWith()
public class WorkTest {
@Tested
@Mocked
Work work;
private ExecutorService executor;
@Before
public void initThread() {
executor = new MockUp<ThreadPoolExecutor>() {
@Mock
public void execute(Runnable command) {
();
}
}.getMockInstance();
}
@Test
public void testTask() {
final OtherVO otherVO = new OtherVO();
new Expectations() { // mock OtherVO的行为
{
();
result = "zero";
}
};
new Expectations() {
{
(work, "otherVO", otherVO);
}
};
// --- 通过以上方式可以将mock出来的otherVO设置到work中,当然可以采取其它简便方式
new Expectations() {
{
(work, "executor", executor);
// --- 将mock出来executor设置到work中
}
};
();
}
}
另一种简单方式:
@RunWith()
public class WorkTest {
@Tested
@Mocked
Work work;
@Test
public void testTask() {
final OtherVO otherVO = new OtherVO();
new Expectations() { // mock OtherVO的行为
{
();
result = "zero";
}
};
new Expectations() {
{
(work, "otherVO", otherVO);
}
};
// --- 通过以上方式可以将mock出来的otherVO设置到work中,当然可以采取其它简便方式
new MockUp<ThreadPoolExecutor>() {
@Mock
public void execute(Runnable command) {
();
}
};
();
}
}