Reputation: 1329
I am using RxJava in my android project and I'm actually starting unit testing my code.
I have following Observable method which I'm going to test
private Observable<Boolean> changeMyString (@NonNull String testString) {
return OneClass
.doSth1(testString)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(testString2 -> Observable.create(
subscriber -> {
manager.setTestString2(testString2);
AnotherClass
.doSth2(testString2)
.subscribe(
testString3 -> {
manager.setTestString3(testString3);
subscriber.onNext(success);
},
subscriber::onError,
subscriber::onCompleted
);
}
));
OneClass.java doSth1(String testString)
private Observable<Object> doSth1 (@NonNull String testString) {
return Observable.create(subscriber -> {
try {
testString = "CHANGEDSTRING"
subscriber.onNext(testString);
subscriber.onCompleted();
}
catch (Exception e) {
subscriber.onError(e);
}
});
}
AnotherClass.java doSth2(Object someObject)
public Observable<String> doSth2 (@NonNull Object someObject) {
return Observable.create(subscriber -> {
String changeText = preferences.getString(ANYSTRING, null); //preferences = SharedPrefences
if (StringHelper.isEmpty(changeText)) {
subscriber.onCompleted();
return;
}
try {
String finishedString = "WE ARE DONE! " + someObject.toString();
subscriber.onNext(finishedString);
subscriber.onCompleted();
}
catch (Exception e) {
subscriber.onError(e);
}
});
}
My Test case looks like the following:
TestSubscriber<Boolean> testSubscriber = new TestSubscriber<>();
ClassToTest.changeMyString("TESTSTRING").subscribe(testSubscriber);
When I debug my Code it's not reaching this part here:
...
.flatMap(testString2 -> Observable.create(
subscriber -> {
manager.setTestString2(testString2);
AnotherClass
.doSth2(testString2)
.subscribe(
testString3 -> {
manager.setTestString3(testString3);
subscriber.onNext(success);
},
subscriber::onError,
subscriber::onCompleted
);
}
));
How can I write a Unit test for this case? I can't figure it out, why it's not working...
Thanks for your help guys!
Alban
Upvotes: 0
Views: 1256
Reputation: 421
Creating a new Observable stream inside a onSubscribe is generally a bad idea.
You should consider something like this:
OneClass
.doSth1(testString)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(testString2 -> manager.setTestString2(testString2))
.flatMap(testString2 -> AnotherClass.doSth2(testString2))
.doOnNext(testString3 -> manager.setTestString3(testString3))
.map(setTestString3 -> true);
From what I see in your code, this should give you what you want.
Upvotes: 1
Reputation: 11515
Instead of using directly Schedulers, you may want to inject it and use TestScheduler
instead. It will allow your to controle executions. (as for an unit test, it may be complicated to deal with others schedulers)
For more information on the TestScheduler
: How to use TestScheduler in RxJava
class YourClass {
private final Scheduler ioScheduler;
private final Scheduler uiScheduler;
public YourClass(Scheduler ioScheduler, Scheduler uiScheduler) {
this.ioScheduler = ioScheduler;
this.uiScheduler = uiScheduler;
}
private Observable<Boolean> changeMyString (@NonNull String testString) {
return OneClass.doSth1(testString)
.subscribeOn(ioScheduler)
.observeOn(uiScheduler)
.doOnNext(str -> manager.setTestString2(str))
.flatMap(testString2 -> AnotherClass
.doSth2(testString2))
.doOnNext(str -> manager.setString3(str));
}
}
Then in your test, you can inject a TestScheduler
instead :
@Test
public void example() {
TestScheduler ui = new TestScheduler();
TestScheduler io = new TestScheduler();
YourClass hello = new YourClass(io, ui);
TestSubscriber subscriber = new TestSubscriber();
hello.changeMyString("stuff").subscribe(subscriber);
io.advanceByTime(2, SECONDS);
ui.advanceByTime(2, SECONDS);
// perform check on subscriber here
}
Please note that I refactored your code as you should avoid nested subscription.
Upvotes: 2