在RxJs中使用TestScheduler测试主题

时间:2014-11-27 14:00:15

标签: javascript unit-testing rxjs reactive-extensions-js

我正在使用RxJ来计算在特定时间窗口内到达的数据包数量。我的代码基本上是这样的:

var packetSubject = new Rx.Subject();
var packetsInWindow = [];

function startMonitoring() {
    var subscription = packetSubject
        .windowWithTime(1000)
        .select(function(window) {
            window.toArray().subscribe(function(elements) {
                packetsInWindow.push(elements.length);
            });
        })
        .subscribe();
}

function newPacket(packet) {
    packetSubject.onNext(packet);
}

如何使用Rx TestScheduler对此代码进行单元测试?我找不到任何合适的测试主题的例子。

2 个答案:

答案 0 :(得分:4)

看看这个例子:

   var x = 0,
       scheduler = new Rx.TestScheduler();

   var subject = new Rx.Subject();
   subject.throttle(100, scheduler).subscribe(function (value) {
       x = value;
   });

   scheduler.scheduleWithAbsolute(0, function () {
       subject.onNext(1);//trigger first event with value 1
   });
   scheduler.scheduleWithAbsolute(50, function () {
       expect(x).toEqual(0);//value hasn't been updated
   });
   scheduler.scheduleWithAbsolute(200, function () {
       expect(x).toEqual(1);//value update after throttle's windowDuration 
   });

   scheduler.start();

https://emmkong.wordpress.com/2015/03/18/how-to-unit-test-rxjs-throttle-with-rx-testscheduler/

答案 1 :(得分:0)

使用RxJs 4.x,您可以在TestScheduler上调用advanceBy。可以在安装过程中注入TestScheduler。我已经写过blog post了。

以下是示例。

    var throttleWindowDuration = 2 * 1000; /* 2 seconds */

    function throttleTest() {
      var unthrottledStream = new Rx.Subject();
      var source = unthrottledStream.throttle(throttleWindowDuration);
      var result = {
        emitCounter: 0,
        unthrottledStream
      };

      var subscription = source.subscribe(
        function() {
          result.emitCounter++;
        });

      return result;
    }

    describe('run with test scheduler', function() {
      var testScheduler;
      var throttleSpy;

      beforeAll(function() {
        testScheduler = new Rx.TestScheduler();
        var originalThrottle = Rx.Observable.prototype.throttle;
        throttleSpy = spyOn(Rx.Observable.prototype, 'throttle')
          .and.callFake(function(dueTime) {
            return originalThrottle.call(this, dueTime, testScheduler);
          });
      });

      afterAll(function() {
        throttleSpy.and.callThrough();
      });

      it('advancing testScheduler allows to test throttling synchronously', function() {
        var throttleTestResult = throttleTest();

        //throttled stream will not emit if scheduler clock is at zero
        testScheduler.advanceBy(1);
        throttleTestResult.unthrottledStream.onNext();
        throttleTestResult.unthrottledStream.onNext();
        throttleTestResult.unthrottledStream.onNext();

        testScheduler.advanceBy(throttleWindowDuration);
        throttleTestResult.unthrottledStream.onNext();
        throttleTestResult.unthrottledStream.onNext();

        testScheduler.advanceBy(throttleWindowDuration);
        throttleTestResult.unthrottledStream.onNext();

        testScheduler.advanceBy(throttleWindowDuration);
        throttleTestResult.unthrottledStream.onNext();

        expect(throttleTestResult.emitCounter).toBe(4);
      });
    });

    describe('run without test scheduler', function() {
      it('without test scheduler the emit counter will stay at 1 ' 
        + 'as throttle duration is not elapsed', function() {
        var throttleTestResult = throttleTest();

        throttleTestResult.unthrottledStream.onNext();
        throttleTestResult.unthrottledStream.onNext();
        throttleTestResult.unthrottledStream.onNext();
        throttleTestResult.unthrottledStream.onNext();
        expect(throttleTestResult.emitCounter).toBe(1);
      });
    });

使用RxJs 5,一切都简单得多。您可以像使用jasmine.clock一样测试其他基于JavaScript的时间操作。 我已在blog post

中演示了该解决方案