2016-09-07 71 views
0

我在我的android項目中使用RxJava,實際上我正在開始單元測試我的代碼。如何測試複雜的RxJava Observables

我具有以下其中我要去測試

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(字符串的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(對象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); 
     } 
    }); 
} 

我的測試用例如下所示:

TestSubscriber<Boolean> testSubscriber = new TestSubscriber<>(); 
ClassToTest.changeMyString("TESTSTRING").subscribe(testSubscriber); 

當我調試我的代碼,它不是在這裏達到這個部分:

... 
.flatMap(testString2 -> Observable.create(
     subscriber -> { 
      manager.setTestString2(testString2); 
      AnotherClass 
       .doSth2(testString2) 
       .subscribe(
        testString3 -> { 
         manager.setTestString3(testString3); 
         subscriber.onNext(success); 
        }, 
        subscriber::onError, 
        subscriber::onCompleted 
       ); 
     } 
    )); 

我怎麼能寫出這種情況下的單元測試?我無法弄清楚,爲什麼它不工作...

感謝您的幫助傢伙!

阿爾

回答

2

而不是使用直接調度器,你可能要注入並使用TestScheduler代替。它會讓你控制執行。 (作爲一個單元測試,它可能是複雜的和別人打交道調度)

有關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)); 
     } 
} 
在您的測試

然後,你可以注入一個TestScheduler代替:

@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 
    } 

請注意,我重構了您的代碼,因爲您應該避免嵌套訂閱。

+0

對於這個解決方案,我必須改變很多我的整個項目。我正在使用帶有靜態方法的私有構造函數,該方法調用方法「changeMyString()」 – NullPointer

+0

因此,您的項目不是模塊化的,並且不容易更改(例如,用於測試目的!)。 您仍然可以使用RxPlugins注入調度程序,但不推薦用於測試。 – dwursteisen

+0

我編輯了我的問題。現在你可以看到我的其他方法調用正在做什麼。否則,你可以幫助我嗎? – NullPointer

1

在onSubscribe內創建一個新的Observable流通常是一個壞主意。

你應該考慮這樣的事情:

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); 

從我在你的代碼中看到,這應該給你想要的東西。

+0

這一個不工作。它不會調用「AnotherClass.doSth2(testString2)」 - 方法....我真的不知道我在做什麼錯誤 – NullPointer

+0

何,不是嗎?你確定OneClass.doSth1(...)發出至少一個項目嗎? 也許你向我們提供了這些方法在做什麼? – cambierr

+0

我編輯了我的問題,以便了解這些方法在做什麼 – NullPointer