我正在尝试使用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的东西。
我怎样才能完成它?是否有任何调度程序不会因此而崩溃?
答案 0 :(得分:21)
我也在使用调度程序线程,但是在我的测试SetUp和TearDown中。
@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();
}
这会有帮助吗?
答案 1 :(得分:5)
我最后为此添加了转换和“味道注入类”,有一个类使用prod / debug版本的main,并使用test flavor文件夹中的另一个类来测试Schedulers.immediate()
。
正常风味的类:
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();
}
}
测试风味类:
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 -> { })
答案 2 :(得分:3)
在我们的实践中,我们尽量避免在Presenter中使用#include <codecvt>
#include <iostream>
#include <locale>
std::locale const utf8("en_US.UTF-8");
// Convert UTF-8 byte string to wstring
std::wstring to_wstring(std::string const& s) {
std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
return conv.from_bytes(s);
}
// Convert wstring to UTF-8 byte string
std::string to_string(std::wstring const& s) {
std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
return conv.to_bytes(s);
}
// Converts a UTF-8 encoded string to upper case
std::string tou(std::string const& s) {
auto ss = to_wstring(s);
for (auto& c : ss) {
c = std::toupper(c, utf8);
}
return to_string(ss);
}
void test_utf8(std::ostream& os) {
os << tou("foo" ) << std::endl;
os << tou("#foo") << std::endl;
os << tou("ßfoo") << std::endl;
os << tou("Éfoo") << std::endl;
}
int main() {
test_utf8(std::cout);
}
,因为它是AndroidSchedulers.mainThread()
实现的详细信息。你也可以这样做。
虽然我们使用的是Robolectric,但无论如何它都可以在我们的测试中使用。
答案 3 :(得分:2)
是的,在junit测试中没有android.jar意味着没有Loopers。如果您使用Dagger,您可以将模拟调度程序注入测试,并将真正的调度程序注入源代码。您也可以使用Mockito之类的东西来模拟调度程序。另外像@Artem Zinnatullin建议的那样,Robolectric解决了这个问题。使用Android Studio很容易设置Robolectric 3。