Mockito:验证来自内部匿名的方法调用 class
Mockito: verifying method call from internal anonymous class
我有一个正在测试的 class,其中包含一个具有内部匿名 class 的方法。匿名class中的一个方法调用了被测class中的一个方法,但是Mockito似乎没有意识到这一点。
public class ClassUnderTest {
Dependency dependency;
public ClassUnderTest(Dependency d) {
dependency = d;
}
public void method() {
dependency.returnsObservable().observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io()).subscribe(new Observer<SupportClass> {
/* Other methods omitted */
public void onComplete() {
outerMethod();
})
}
public void outerMethod() {
blah;
}
}
我的测试代码:
public class TestClass {
ClassUnderTest underTest;
Dependency dependency;
@Before
public void setUp() throws Exception {
dependency = Mockito.mock(Dependency.class);
underTest = Mockito.spy(new ClassUnderTest(dependency));
}
@Test
public void method() throws
Mockito.when(dependency.returnObservable()).thenReturn(Observable.just(new SupportClass());
Mockito.doNothing().when(underTest).outerMethod();
underTest.method();
Mockito.verify(underTest).outerMethod();
}
}
出于某种我似乎无法弄清楚的原因,Mockito 无法检测到正在调用 outerMethod(),即使我已经通过调试器中的逐行单步执行手动验证。我还验证了对依赖对象 returns 的调用是具有正确内容的正确可观察对象,并且确实调用了 onComplete() 和 outerMethod() 方法。我只是很困惑为什么 Mockito 没有检测到它。
这是它吐出的错误:
Wanted but not invoked:
classUnderTest.outerMethod();
-> at (file and line number)
However, there was exactly 1 interaction with this mock:
classUnderTest.method();
-> at (file and line number)
有什么明显的我遗漏的吗?
您正在调度程序之间切换,因此在测试时可能会导致一些问题(您的代码可能会到达 verify
方法 在 调用实际方法之前
检查 this article 解释如何使用 RxJava 和 Mockito 测试异步代码
TL;DR
添加一个 TestRule
将所有调度程序设置为 trampoline
以便它同步运行:
public class TrampolineSchedulerRule implements TestRule {
@Override
public Statement apply(final Statement base, Description d) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
RxJavaPlugins.setIoSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxJavaPlugins.setComputationSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxJavaPlugins.setNewThreadSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxAndroidPlugins.setInitMainThreadSchedulerHandler(
scheduler -> Schedulers.trampoline());
try {
base.evaluate();
} finally {
RxJavaPlugins.reset();
RxAndroidPlugins.reset();
}
}
};
}
}
我有一个正在测试的 class,其中包含一个具有内部匿名 class 的方法。匿名class中的一个方法调用了被测class中的一个方法,但是Mockito似乎没有意识到这一点。
public class ClassUnderTest {
Dependency dependency;
public ClassUnderTest(Dependency d) {
dependency = d;
}
public void method() {
dependency.returnsObservable().observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io()).subscribe(new Observer<SupportClass> {
/* Other methods omitted */
public void onComplete() {
outerMethod();
})
}
public void outerMethod() {
blah;
}
}
我的测试代码:
public class TestClass {
ClassUnderTest underTest;
Dependency dependency;
@Before
public void setUp() throws Exception {
dependency = Mockito.mock(Dependency.class);
underTest = Mockito.spy(new ClassUnderTest(dependency));
}
@Test
public void method() throws
Mockito.when(dependency.returnObservable()).thenReturn(Observable.just(new SupportClass());
Mockito.doNothing().when(underTest).outerMethod();
underTest.method();
Mockito.verify(underTest).outerMethod();
}
}
出于某种我似乎无法弄清楚的原因,Mockito 无法检测到正在调用 outerMethod(),即使我已经通过调试器中的逐行单步执行手动验证。我还验证了对依赖对象 returns 的调用是具有正确内容的正确可观察对象,并且确实调用了 onComplete() 和 outerMethod() 方法。我只是很困惑为什么 Mockito 没有检测到它。
这是它吐出的错误:
Wanted but not invoked:
classUnderTest.outerMethod();
-> at (file and line number)
However, there was exactly 1 interaction with this mock:
classUnderTest.method();
-> at (file and line number)
有什么明显的我遗漏的吗?
您正在调度程序之间切换,因此在测试时可能会导致一些问题(您的代码可能会到达 verify
方法 在 调用实际方法之前
检查 this article 解释如何使用 RxJava 和 Mockito 测试异步代码
TL;DR
添加一个 TestRule
将所有调度程序设置为 trampoline
以便它同步运行:
public class TrampolineSchedulerRule implements TestRule {
@Override
public Statement apply(final Statement base, Description d) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
RxJavaPlugins.setIoSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxJavaPlugins.setComputationSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxJavaPlugins.setNewThreadSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxAndroidPlugins.setInitMainThreadSchedulerHandler(
scheduler -> Schedulers.trampoline());
try {
base.evaluate();
} finally {
RxJavaPlugins.reset();
RxAndroidPlugins.reset();
}
}
};
}
}