cod*_*ner 8 android unit-testing rx-android retrofit2 rx-java2
我刚学会了RxAndroid,但不幸的是我研究过的这本书没有涵盖任何单元测试.我在谷歌上搜索了很多,但没有找到任何简单的教程,以精确的方式涵盖RxAndroid单元测试.
我基本上使用RxAndroid和Retrofit 2编写了一个小的REST API.这是ApiManager类:
public class MyAPIManager {
private final MyService myService;
public MyAPIManager() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder b = new OkHttpClient.Builder();
b.readTimeout(35000, TimeUnit.MILLISECONDS);
b.connectTimeout(35000, TimeUnit.MILLISECONDS);
b.addInterceptor(logging);
OkHttpClient client = b.build();
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://192.168.1.7:8000")
.client(client)
.build();
myService = retrofit.create(MyService.class);
}
public Observable<Token> getToken(String username, String password) {
return myService.getToken(username, password)
.subscribeOn(Schedulers.io());
.observeOn(AndroidSchedulers.mainThread());
}
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试创建一个单元测试getToken.这是我的样本测试:
public class MyAPIManagerTest {
private MyAPIManager myAPIManager;
@Test
public void getToken() throws Exception {
myAPIManager = new MyAPIManager();
Observable<Token> o = myAPIManager.getToken("hello", "mytoken");
o.test().assertSubscribed();
o.test().assertValueCount(1);
}
}
Run Code Online (Sandbox Code Playgroud)
由于subscribeOn(Schedulers.io)上面的测试没有在主线程上运行,因为它返回0值.如果我删除subscribeOn(Schedulers.io)从MyAPIManager那么它运行良好,并返回值1.有没有办法测试Schedulers.io?
很好的问题,当然还有一个在社区中缺乏大量报道的话题.我想分享一些我个人使用的解决方案并且非常精彩.这些被认为是RxJava 2,但它们可以在不同的名称下使用RxJava 1.如果需要,您肯定会找到它.
所以实际上的Rx提供了一种机制,以改变由内而外的静态方法提供的调度Schedulers和AndroidSchedulers.这些是例如:
RxJavaPlugins.setComputationSchedulerHandler
RxJavaPlugins.setIoSchedulerHandler
RxJavaPlugins.setNewThreadSchedulerHandler
RxJavaPlugins.setSingleSchedulerHandler
RxAndroidPlugins.setInitMainThreadSchedulerHandler
Run Code Online (Sandbox Code Playgroud)
这些做的很简单.它们确保在您调用时,即Schedulers.io()返回的调度程序是您在处理程序集中提供的调度程序setIoSchedulerHandler.您想使用哪个调度程序?好吧你想要的Schedulers.trampoline().这意味着代码将在以前的相同线程上运行.如果所有调度程序都在trampoline调度程序中,那么所有调度程序都将在该JUnit线程上运行.运行测试后,您可以通过调用以下方法清除整个测试:
RxJavaPlugins.reset()
RxAndroidPlugins.reset()
Run Code Online (Sandbox Code Playgroud)
我认为最好的方法是使用JUnit规则.这是一个可能的(抱歉kotlin语法):
class TrampolineSchedulerRule : TestRule {
private val scheduler by lazy { Schedulers.trampoline() }
override fun apply(base: Statement?, description: Description?): Statement =
object : Statement() {
override fun evaluate() {
try {
RxJavaPlugins.setComputationSchedulerHandler { scheduler }
RxJavaPlugins.setIoSchedulerHandler { scheduler }
RxJavaPlugins.setNewThreadSchedulerHandler { scheduler }
RxJavaPlugins.setSingleSchedulerHandler { scheduler }
RxAndroidPlugins.setInitMainThreadSchedulerHandler { scheduler }
base?.evaluate()
} finally {
RxJavaPlugins.reset()
RxAndroidPlugins.reset()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在单元测试的顶部,您只需要声明一个@Rule使用此类注释并使用此类实例化的公共属性:
@Rule
public TrampolineSchedulerRule rule = new TrampolineSchedulerRule()
Run Code Online (Sandbox Code Playgroud)
在kotlin
@get:Rule
val rule = TrampolineSchedulerRule()
Run Code Online (Sandbox Code Playgroud)
另一种可能性是在您的类中注入调度程序,因此在测试时您可以再次注入,Schedulers.trampoline()并且在您的应用程序中,您可以注入正常的调度程序.这可能会有一段时间,但是当你需要为一个简单的类注入大量的调度程序时,它很快就会变得很麻烦.这是一种做到这一点的方法
public class MyAPIManager {
private final MyService myService;
private final Scheduler io;
private final Scheduler mainThread;
public MyAPIManager(Scheduler io, Scheduler mainThread) {
// initialise everything
this.io = io;
this.mainThread = mainThread;
}
public Observable<Token> getToken(String username, String password) {
return myService.getToken(username, password)
.subscribeOn(io);
.observeOn(mainThread);
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我们现在可以告诉班级实际的调度程序.在你的测试中,你会做类似的事情:
public class MyAPIManagerTest {
private MyAPIManager myAPIManager;
@Test
public void getToken() throws Exception {
myAPIManager = new MyAPIManager(
Schedulers.trampoline(),
Schedulers.trampoline());
Observable<Token> o = myAPIManager.getToken("hello", "mytoken");
o.test().assertSubscribed();
o.test().assertValueCount(1);
}
}
Run Code Online (Sandbox Code Playgroud)
关键点是:
您希望它在Schedulers.trampoline()调度程序上确保所有内容都在JUnit线程上运行
您需要能够在测试时修改调度程序.
就这样.希望能帮助到你.
================================================== =======
这是我在以上Kotlin示例之后使用的Java版本:
public class TrampolineSchedulerRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return new MyStatement(base);
}
public class MyStatement extends Statement {
private final Statement base;
@Override
public void evaluate() throws Throwable {
try {
RxJavaPlugins.setComputationSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setIoSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setNewThreadSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setSingleSchedulerHandler(scheduler -> Schedulers.trampoline());
RxAndroidPlugins.setInitMainThreadSchedulerHandler(scheduler -> Schedulers.trampoline());
base.evaluate();
} finally {
RxJavaPlugins.reset();
RxAndroidPlugins.reset();
}
}
public MyStatement(Statement base) {
this.base = base;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1298 次 |
| 最近记录: |