使用RxJava2,我有一个桥接反应式和非反应式世界的类。在此类中,有一个覆盖的方法,该方法可能经过长时间处理后会返回一些值。此处理使用Single.create(emitter -> ...)
嵌入到响应世界。
处理时间对我来说至关重要,因为在业务逻辑,处理运行时还是处理完成(或取消)之后是否出现第二个订户方面存在差异。 < / p>
现在我要测试此类-因此,我需要较长的处理时间才能仅使用虚拟。 RxJava的TestScheduler
抢救了!
要为桥接的基类创建一个模拟延迟的测试实现,我需要在TestScheduler上进行阻塞(!)调用,在该调用中,时间的提前在一个单独的线程上触发。 (否则,将不会触发时间的提前。)
我的问题是,我需要将时间提前至少延迟到“昂贵的计算”受阻为止-否则,时间得更改之前操作员变得活跃,因此,它等待直到永远不会发生的另一次前进。
我可以通过在提前致电之前致电Thread.sleep(100)
来解决此问题-但这对我来说似乎有点丑陋……要等多久?对于多个测试,该时间加起来,但是由于计时问题而失败了……。
有人知道如何以一种希望更干净的方式测试这种情况吗? 谢谢!
import io.reactivex.Completable;
import io.reactivex.Single;
import io.reactivex.observers.TestObserver;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.schedulers.TestScheduler;
import java.util.concurrent.TimeUnit;
public class TestSchedulerBlocking {
public static void main(String[] args) throws Exception {
TestScheduler testScheduler = new TestScheduler();
// the task - in reality, this is a task with a overridden method returning some value, where I need to delay the return in a test-implementation.
Single<String> single = Single.create(emitter -> {
System.out.println("emitting on " + Thread.currentThread() + " ...");
// This is the core of my problem: I need some way to test a (synchronous) delay before the next line executes
// (e.g. method returns, or, in another case, an exception is thrown).
// Thread.sleep(<delay>) would be straight forward, but I want to use TestScheduler's magic time-advancing in my tests...
// Using the usual non-blocking methods of RX, everything works fine for testing using the testScheduler, but here it doesn't help.
// Here I need to synchronize it somehow, that the advancing in time is done *after* this call is blocking.
// I tried a CountDownLatch in doOnSubscribe, but apparently, that's executed too early for me - I'd need doAfterSubscribe or so...
// Final word on architecture: I'm dealing with the bridging of the reactive to the non-reactive world, so I can't just change the architecture.
Completable.complete()
.delay(3, TimeUnit.SECONDS, testScheduler)
.doOnSubscribe(__ -> System.out.println("onSubcribe: completable"))
.blockingAwait();
System.out.println("<< blocking released >>");
// this has to be delayed! Might be, for example, a return or an exception in real world.
emitter.onSuccess("FooBar!");
});
System.out.println("running the task ...");
TestObserver<String> testObserver = single.doOnSubscribe(__ -> System.out.println("onSubcribe: single"))
.subscribeOn(Schedulers.newThread())
.test();
// Without this sleep, the advancing in testScheduler's time is done *before* the doIt() is executed,
// and therefore the blockingAwait() blocks until infinity...
System.out.println("---SLEEPING---");
Thread.sleep(100);
// virtually advance the blocking delay
System.out.println("---advancing time---");
testScheduler.advanceTimeBy(3, TimeUnit.SECONDS);
// wait for the task to complete
System.out.println("await...");
testObserver.await();
// assertions on task results, etc.
System.out.println("finished. now do some testing... values (expected [FooBar!]): " + testObserver.values());
}
}
[注意:昨天我以更为复杂和冗长的方式提出了这个问题-但由于办公室里太热,而且存在一些缺陷和错误。因此,我已将其删除,现在它更加集中于实际问题。]
答案 0 :(得分:0)
如果我正确理解了您的问题,则说明您拥有长期运行的服务,并且希望能够测试将受到长期运行服务影响的服务的订阅。我已通过以下方式进行处理。
使用TestScheduler
来控制其服务时间,从而按需定义服务。然后使用相同的测试计划程序定义测试刺激。
这模拟了阻止实体。不要使用“阻止”。
Single<String> single = Observable.timer( 3, TimeUnit.SECONDS, scheduler )
.doOnNext( _l -> {} )
.map( _l -> "FooBar!" )
.take( 1 )
.toSingle();
// set up asynchronous operations
Observable.timer( 1_500, TimeUnit.MILLISECONDS, scheduler )
.subscribe( _l -> performTestAction1() );
Observable.timer( 1_900, TimeUnit.MILLISECONDS, scheduler )
.subscribe( _l -> performTestAction2() );
Observable.timer( 3_100, TimeUnit.MILLISECONDS, scheduler )
.subscribe( _l -> performTestAction3() );
System.out.println("running the task ...");
TestObserver<String> testObserver = single.doOnSubscribe(__ -> System.out.println("onSubcribe: single"))
.subscribeOn(Schedulers.newThread())
.test();
// virtually advance the blocking delay
System.out.println("---advancing time---");
testScheduler.advanceTimeBy(4, TimeUnit.SECONDS);
您应该看到发生performTestAction1()
,然后发生performTestAction2()
,然后single
完成,然后出现performTestAction3()
。所有这些都是由测试计划程序驱动的。