带有 JUnit 的 RxJava2:测试中没有抛出异常
RxJava2 with JUnit: no exceptions thrown in tests
下面的代码在 JUnit 环境中 运行 时不会崩溃。但是在应用程序中 运行 时它会崩溃。我可以在控制台中看到错误日志,但测试标记为已通过。
@Test
public void test() {
Observable observable = Observable.error(new RuntimeException());
observable.subscribe();
}
所以,问题是:如何让它在 JUnit 中崩溃。因为是的,如果某些东西在应用程序中不起作用,那么如果它在单元测试中也不起作用也是一件好事 :)
在这个例子中,我可以直接访问可观察对象。但在我的真实测试中,我没有那个。真正的可观察对象只是被测试的 类 的内部细节。我最多能做的就是注入调度器什么的。
那么,如何在无法直接访问 observable 的情况下使其崩溃?
此外,我刚刚检查过这段代码也没有崩溃:
@Test
public void test() {
Observable observable = Observable.error(new RuntimeException());
observable.subscribe(new Consumer() {
@Override
public void accept(Object o) throws Exception {
throw new RuntimeException();
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
throw new RuntimeException();
}
});
}
Observable observable = Observable.error(new RuntimeException());
TestSubscriber testSubscriber = TestSubscriber.create();
observable.subscribe(testSubscriber);
testSubscriber.assertTerminalEvent();
testSubscriber.assertError(RuntimeException.class);
根据 akarnokd 的说法,这是 RxJava2 特有的问题。
"Such usages no longer throw synchronously in 2.x but end up in the plugin handler for errors."
可以检查此代码是否抛出任何错误
public static List<Throwable> trackPluginErrors() {
final List<Throwable> list = Collections.synchronizedList(new ArrayList<Throwable>());
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(Throwable t) {
list.add(t);
}
});
return list;
}
我用来解决这个问题的一个小技巧是创建一个 JUnit4 TestRule class,它设置一个自定义的 RxJava 错误处理程序,以便在发生未处理的 RxJava 错误时抛出:
/**
* A rule that detects RxJava silent errors and reports them to JUnit
(by throwing them).
*/
public class RxErrorRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Consumer<? super Throwable> previous = RxJavaPlugins.getErrorHandler();
AtomicReference<Throwable> result = setupErrorHandler();
try {
base.evaluate();
} finally {
RxJavaPlugins.setErrorHandler(previous);
}
if (result.get() != null) {
throw result.get();
}
}
};
}
private AtomicReference<Throwable> setupErrorHandler() {
AtomicReference<Throwable> result = new AtomicReference<>();
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
result.set(throwable);
}
});
return result;
}
}
并且在单元测试中:
public class YourRxTest {
@Rule
public RxErrorRule errorRule = new RxErrorRule();
// ...
}
下面的代码在 JUnit 环境中 运行 时不会崩溃。但是在应用程序中 运行 时它会崩溃。我可以在控制台中看到错误日志,但测试标记为已通过。
@Test
public void test() {
Observable observable = Observable.error(new RuntimeException());
observable.subscribe();
}
所以,问题是:如何让它在 JUnit 中崩溃。因为是的,如果某些东西在应用程序中不起作用,那么如果它在单元测试中也不起作用也是一件好事 :)
在这个例子中,我可以直接访问可观察对象。但在我的真实测试中,我没有那个。真正的可观察对象只是被测试的 类 的内部细节。我最多能做的就是注入调度器什么的。
那么,如何在无法直接访问 observable 的情况下使其崩溃?
此外,我刚刚检查过这段代码也没有崩溃:
@Test
public void test() {
Observable observable = Observable.error(new RuntimeException());
observable.subscribe(new Consumer() {
@Override
public void accept(Object o) throws Exception {
throw new RuntimeException();
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
throw new RuntimeException();
}
});
}
Observable observable = Observable.error(new RuntimeException());
TestSubscriber testSubscriber = TestSubscriber.create();
observable.subscribe(testSubscriber);
testSubscriber.assertTerminalEvent();
testSubscriber.assertError(RuntimeException.class);
根据 akarnokd 的说法,这是 RxJava2 特有的问题。
"Such usages no longer throw synchronously in 2.x but end up in the plugin handler for errors."
可以检查此代码是否抛出任何错误
public static List<Throwable> trackPluginErrors() {
final List<Throwable> list = Collections.synchronizedList(new ArrayList<Throwable>());
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(Throwable t) {
list.add(t);
}
});
return list;
}
我用来解决这个问题的一个小技巧是创建一个 JUnit4 TestRule class,它设置一个自定义的 RxJava 错误处理程序,以便在发生未处理的 RxJava 错误时抛出:
/**
* A rule that detects RxJava silent errors and reports them to JUnit
(by throwing them).
*/
public class RxErrorRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Consumer<? super Throwable> previous = RxJavaPlugins.getErrorHandler();
AtomicReference<Throwable> result = setupErrorHandler();
try {
base.evaluate();
} finally {
RxJavaPlugins.setErrorHandler(previous);
}
if (result.get() != null) {
throw result.get();
}
}
};
}
private AtomicReference<Throwable> setupErrorHandler() {
AtomicReference<Throwable> result = new AtomicReference<>();
RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
result.set(throwable);
}
});
return result;
}
}
并且在单元测试中:
public class YourRxTest {
@Rule
public RxErrorRule errorRule = new RxErrorRule();
// ...
}