【发布时间】:2017-08-02 16:38:14
【问题描述】:
我正在努力解决如何在具有许多运算符的 RxJava 流中测试复杂逻辑。我发现,如果我有复杂的逻辑并且将许多具有复杂逻辑的运算符串在一起,那么单元测试流将成为一场噩梦,因为要涵盖的案例组合太多。
这是我所描述的一个例子:
Observable<ObjectA> observable = myRepository
.fetchA()
.flatMap(new Func1<ObjectA, Observable<ObjectA>>() {
@Override
public Observable<ObjectA> call(final ObjectA object) {
if (object.isAvailable()) {
//do something
return myRepository
.fetchAnotherThing();
} else {
//do something else
return myRepositor
.fetchADifferentThing();
}
}
})
.flatMap(new Func1<ObjectA, Observable<ObjectA>>() {
@Override
public Observable<ObjectA> call(final ObjectA object) {
if (object.isFull()) {
//do something
return myRepository
.doThingA();
} else {
//do something else
return myRepository
.doThingB();
}
}
});
如果我想为此编写一个单元测试,我需要编写至少 4 种测试方法,以便涵盖条件逻辑的所有组合。
通常当发生这种情况时,我会编写一个自定义类来处理逻辑,然后对该类进行单元测试。所以上面的代码可能会变成这样:
public class MyFunc implements Func1<ObjectA, Observable<ObjectA>> {
@Override
public Observable<ObjectA> call(final ObjectA object) {
//The logic that was formerly in an anonymous Func1 is now here
if (object.isAvailable()) {
//do something
return myRepository.fetchAnotherThing();
} else {
//do something else
return myRepository.fetchADifferentThing();
}
}
}
public class MyOtherFunc implements Func1<ObjectA, Observable<ObjectA>> {
@Override
public Observable<ObjectA> call(final ObjectA object) {
//The logic that was formerly in an anonymous Func1 is now here
if (object.isFull()) {
//do something
return myRepository.doThingA();
} else {
//do something else
return myRepository.doThingB();
}
}
}
现在 MyFunc 和 MyOtherFunc 现在可以自行进行单元测试,我可以单独验证逻辑是否正确。然后我的原始代码可以转换成这样的:
Observable<ObjectA> observable = myRepository
.fetchA()
.flatMap(myFunc)
.flatMap(myOtherFunc);
这当然看起来更简洁,并且减轻了我对链的单元测试的需要,以像以前一样处理许多情况,但现在的问题是我如何测试剩下的内容?
如果我模拟 myFunc 和 myOtherFunc 的输出,那么看起来我根本没有真正测试任何东西。另一种选择是使用 myFunc 和 myOtherFunc 的实际实现,但现在我不再进行单元测试,而是进行集成测试,这带来了额外的麻烦。
之前有没有其他人为此苦恼过,如果有,您是如何解决可测试性问题的?
【问题讨论】:
-
如果您为
myFunc和myOtherFunc创建模拟,那么您可以测试a) 时序、b) 错误条件、c) 并行性、d) 组合的变化。例如,当fetchA()发出多个项目时会发生什么?没有项目?
标签: android unit-testing rx-java rx-android