单元测试RxJS Observable.timer使用typescript,karma和jasmine

ste*_*hin 7 unit-testing rxjs5 angular

嗨,我对Angular2,Karma和Jasmine相对较新.目前我正在使用Angular 2 RC4 Jasmine 2.4.x我有一个Angular 2服务,定期调用这样的http服务:

getDataFromDb() { return Observable.timer(0, 2000).flatMap(() => {
        return this.http.get(this.backendUrl)
            .map(this.extractData)
            .catch(this.handleError);
    });
}
Run Code Online (Sandbox Code Playgroud)

现在我想测试功能.出于测试目的,我刚刚在没有Observable.timer的单独函数上测试了"http.get":

const mockHttpProvider = {
    deps: [MockBackend, BaseRequestOptions],
    useFactory: (backend: MockBackend, defaultOptions: BaseRequestOptions) => {
        return new Http(backend, defaultOptions);
    }
}

describe('data.service test suite', () => {
    var dataFromDbExpected: any;

    beforeEachProviders(() => {
        return [
            DataService,
            MockBackend,
            BaseRequestOptions,
            provide(Http, mockHttpProvider),
        ];
    });

    it('http call to obtain data',
        inject(
            [DataService, MockBackend],
            fakeAsync((service: DataService, backend: MockBackend) => {
                backend.connections.subscribe((connection: MockConnection) => {
                    dataFromDbExpected =  'myData';
                    let mockResponseBody: any = 'myData';
                    let response = new ResponseOptions({ body: mockResponseBody });
                    connection.mockRespond(new Response(response));

                });
                const parsedData$ = service.getDataFromDb()
                    .subscribe(response => {
                        console.log(response);
                        expect(response).toEqual(dataFromDbExpected);
                    });
            })));
});
Run Code Online (Sandbox Code Playgroud)

我显然想用Observable.timer测试整个函数.我想有人可能想要使用rxjs框架中的TestScheduler,但是如何判断只重复计时器函数x次?我不会在打字稿上下文中找到任何使用它的文档.

编辑:我正在使用rxjs 5 beta 6

编辑:为Angular 2.0.0最终版本添加了工作示例:

describe('when getData', () => {
    let backend: MockBackend;
    let service: MyService;
    let fakeData: MyData[];
    let response: Response;
    let scheduler: TestScheduler;

    beforeEach(inject([Http, XHRBackend], (http: Http, be: MockBackend) => {
        backend = be;
        service = new MyService(http);
        fakeData = [{myfake: 'data'}];
        let options = new ResponseOptions({ status: 200, body: fakeData });
        response = new Response(options);

        scheduler = new TestScheduler((a, b) => expect(a).toEqual(b));
        const originalTimer = Observable.timer;
        spyOn(Observable, 'timer').and.callFake(function (initialDelay, dueTime) {
            return originalTimer.call(this, initialDelay, dueTime, scheduler);
        });
    }));
    it('Should do myTest', async(inject([], () => {
        backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));
        scheduler.schedule(() => {
            service.getMyData().subscribe(
                myData => {
                    expect(myData.length).toBe(3,
                        'should have expected ...');
                });
        }, 2000, null);
        scheduler.flush();
    })));
});
Run Code Online (Sandbox Code Playgroud)

Sim*_*sch 8

您需要将TestScheduler注入beforeEach部分中的timer方法:

beforeEach(function() {
  this.scheduler = new TestScheduler();
  this.scheduler.maxFrames = 5000; // Define the max timespan of the scheduler
  const originalTimer = Observable.timer;
  spyOn(Observable, 'timer').and.callFake(function(initialDelay, dueTime) {  
    return originalTimer.call(this, initialDelay, dueTime, this.scheduler);
  });
});
Run Code Online (Sandbox Code Playgroud)

之后,您可以完全控制时间scheduleAbsolute:

this.scheduler.schedule(() => {
  // should have been called once
  // You can put your test code here
}, 1999, null);

this.scheduler.schedule(() => {
  // should have been called twice
  // You can put your test code here
}, 2000, null);

this.scheduler.schedule(() => {
  // should have been called three times
  // You can put your test code here
}, 4000, null);

this.scheduler.flush();
Run Code Online (Sandbox Code Playgroud)

您需要scheduler.flush()启动TestScheduler.

编辑:因此,如果您只想测试X次,请按常规使用scheduleAbsolute函数(并使用正确的绝对时间,以毫秒为单位).

edit2:我添加了缺少的调度程序启动

edit3:我改了它,所以应该使用RxJs5

  • 界面似乎已更改。现在,TestScheduler期望在构造函数中使用assertDeepEqual,请参见[link](https://github.com/ReactiveX/rxjs/blob/master/src/testing/TestScheduler.ts)。不过,我有点困惑,在创建TestScheduler时我应该断言什么? (2认同)