2016-09-07 81 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