不依赖于 Android 的 JUnit 调度程序
JUnit Scheduler that doesn't depend on Android
我正在尝试使用 MVP 来增强单元测试并 运行 测试更快(因为我测试的是逻辑而不是 android 代码,所以我避免使用 RobotElectric 之类的东西)。
但我使用的是 RXAndroid,它需要 Looper 来获取 Schedulers.io()
和 AndroidSchedulers.mainThread()
,当我有时尝试 运行 时
class Phone {
public Observable<> sendSms(String number){
//...
}
}
Phone.getInstance().sendSms(phoneNumber)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(phone -> {
mView.dismissProgress();
mView.startCodeView(phone);
}, error -> {
mView.dismissProgress();
mView.showError(error);
});
我得到:
Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.os.Looper.getMainLooper(Looper.java)
at rx.android.schedulers.AndroidSchedulers.<clinit>(AndroidSchedulers.java:27)
... 28 more
我试过了:
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
但它不会工作,因为我想 运行 完整的 JUnit 测试而不是 Roboelectric 或 Espresso 的东西。
我怎样才能完成它?有没有不会因此崩溃的调度程序?
在我们的实践中,我们尽量避免在 Presenter 中使用 AndroidSchedulers.mainThread()
,因为它是 View
实现的细节。你也可以这样做。
虽然我们使用 Robolectric,但无论如何它会在我们的测试中起作用。
是的,在 junit 测试中没有 android.jar 意味着没有 Loopers。如果你使用 Dagger,你可以将一个模拟调度器注入到测试中,并将一个真正的调度器注入到源代码中。您还可以使用 Mockito 之类的东西来模拟调度程序。否则就像@Artem Zinnatullin 建议的那样,Robolectric 解决了这个问题。 Robolectric 3 使用 Android Studio 非常容易设置。
我最终添加了使用转换和 "flavour injection classes" 为此,有一个 class 将主版本用于 prod/debug 版本并在测试版本中使用另一个 class测试文件夹 Schedulers.immediate()
.
普通口味class:
public class Transformer {
public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
return observable -> observable.subscribeOn(getIoScheduler())
.observeOn(getMainScheduler());
}
private static Scheduler getIoScheduler() {
return Schedulers.io();
}
private static Scheduler getMainScheduler() {
return AndroidSchedulers.mainThread();
}
}
测试风味 class:
public class Transformer {
public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
return observable -> observable.subscribeOn(getIoScheduler())
.observeOn(getMainScheduler());
}
private static Scheduler getIoScheduler() {
return Schedulers.immediate() ;
}
private static Scheduler getMainScheduler() {
return Schedulers.immediate() ;
}
}
然后将其与转换一起使用:
mSessionRepository.login(...)
.compose(Transformer.applyIoSchedulers())
.subscribe(session -> { })
我也为此使用调度程序线程,但在我的测试设置和拆卸中。
@Before
public void setUp() throws Exception {
RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
@Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
});
}
@After
public void tearDown() {
RxAndroidPlugins.getInstance().reset();
}
这会有帮助吗?
我正在尝试使用 MVP 来增强单元测试并 运行 测试更快(因为我测试的是逻辑而不是 android 代码,所以我避免使用 RobotElectric 之类的东西)。
但我使用的是 RXAndroid,它需要 Looper 来获取 Schedulers.io()
和 AndroidSchedulers.mainThread()
,当我有时尝试 运行 时
class Phone {
public Observable<> sendSms(String number){
//...
}
}
Phone.getInstance().sendSms(phoneNumber)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(phone -> {
mView.dismissProgress();
mView.startCodeView(phone);
}, error -> {
mView.dismissProgress();
mView.showError(error);
});
我得到:
Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.os.Looper.getMainLooper(Looper.java)
at rx.android.schedulers.AndroidSchedulers.<clinit>(AndroidSchedulers.java:27)
... 28 more
我试过了:
android {
// ...
testOptions {
unitTests.returnDefaultValues = true
}
}
但它不会工作,因为我想 运行 完整的 JUnit 测试而不是 Roboelectric 或 Espresso 的东西。
我怎样才能完成它?有没有不会因此崩溃的调度程序?
在我们的实践中,我们尽量避免在 Presenter 中使用 AndroidSchedulers.mainThread()
,因为它是 View
实现的细节。你也可以这样做。
虽然我们使用 Robolectric,但无论如何它会在我们的测试中起作用。
是的,在 junit 测试中没有 android.jar 意味着没有 Loopers。如果你使用 Dagger,你可以将一个模拟调度器注入到测试中,并将一个真正的调度器注入到源代码中。您还可以使用 Mockito 之类的东西来模拟调度程序。否则就像@Artem Zinnatullin 建议的那样,Robolectric 解决了这个问题。 Robolectric 3 使用 Android Studio 非常容易设置。
我最终添加了使用转换和 "flavour injection classes" 为此,有一个 class 将主版本用于 prod/debug 版本并在测试版本中使用另一个 class测试文件夹 Schedulers.immediate()
.
普通口味class:
public class Transformer {
public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
return observable -> observable.subscribeOn(getIoScheduler())
.observeOn(getMainScheduler());
}
private static Scheduler getIoScheduler() {
return Schedulers.io();
}
private static Scheduler getMainScheduler() {
return AndroidSchedulers.mainThread();
}
}
测试风味 class:
public class Transformer {
public static <T> Observable.Transformer<T, T> applyIoSchedulers() {
return observable -> observable.subscribeOn(getIoScheduler())
.observeOn(getMainScheduler());
}
private static Scheduler getIoScheduler() {
return Schedulers.immediate() ;
}
private static Scheduler getMainScheduler() {
return Schedulers.immediate() ;
}
}
然后将其与转换一起使用:
mSessionRepository.login(...)
.compose(Transformer.applyIoSchedulers())
.subscribe(session -> { })
我也为此使用调度程序线程,但在我的测试设置和拆卸中。
@Before
public void setUp() throws Exception {
RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
@Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
});
}
@After
public void tearDown() {
RxAndroidPlugins.getInstance().reset();
}
这会有帮助吗?