单元测试复杂的Observable流

时间:2017-05-03 17:31:44

标签: angular rxjs reactive-programming observable ngrx

我有以下函数,(我认为)返回一个复合可观察函数:

test(cell) {
   const observ1 = this.store.select('range').flatMap((val: IRange) => {return this.getCellOEE(val.value)});
   const observ2 = this.getCellOEE(cell);
   return Observable.merge(observ1, observ2);
}

我在角度4服务中使用它,并试图用茉莉和业力进行单元测试。

所以我这样嘲笑商店:

class mockStore {
  select(): Observable<IRange> {
    return Observable.of({value: 'daily', start: moment(), end: moment()}, {value: 'monthly', start: moment(), end: moment()})
  }
}

然后我有以下测试:

 it('should update result on store change', fakeAsync(inject(
    [MockBackend, OeeService],
    (backend: MockBackend, s: OeeService) => {
      const urls = [];

      backend.connections.subscribe((connection: MockConnection) => {
        const req: any = connection.request;
        urls.push(req.url);
        if (req.method === RequestMethod.Get && req.url === 'api/getLine/data' req.headers.get('range') === 'daily') {
          connection.mockRespond(new Response(new ResponseOptions({ body: { data: 12 } })));
        }
        if (req.method === RequestMethod.Get && req.url === 'api/getLine/data' &&
          req.headers.get('range') === 'monthly') {
          connection.mockRespond(new Response(new ResponseOptions({ body: { data: 15 } })));
        }
      });
      let value;
      s.test('powders').subscribe(val => {
        value = val;
      })

      tick();
      expect(value).toEqual(12);
      tick();
      expect(value).toEqual(15);
    })
  ));

我希望很清楚我想要实现的目标,所以当最初调用test()函数时,会进行直接的http调用,但是我的模拟商店应该发布params的更改,映射到具有新参数的http请求,然后返回不同的值。

我目前第一次expect()传递,但第二次失败:

  

预计12包含15

所以我觉得有时间问题?我有什么想法可以解决这个问题?我认为测试很重要,因为我可以起诉一些好的旧TDD来证明这种方法是否有效。

更新

这是我的完整单元测试file

1 个答案:

答案 0 :(得分:3)

你是对的,测试有时间问题。到第一个Expect()表达式发生时,模拟Responses都返回了。要修复测试,您可以更改其中一个响应以使用setTimeout(),并在期望子句之间设置tick()到该延迟后的某个时间。

例如:

if (req.method === RequestMethod.Get && req.url === 'api/getLine/data' && req.headers.get('range') === 'monthly') {
    setTimeout(() => { 
        connection.mockRespond(new Response(new ResponseOptions({ body: { data: 15 } })));      }, 100);
}

expect(value).toEqual(12);
tick(100);
expect(value).toEqual(15);

然而,与julia上面所说的类似,更好的测试是将值推入数组并检查各个索引处的值是否正确。在这种情况下,我建议将测试函数中的flatMap()替换为保留顺序的concatMap()。然后,您可以编写多个测试,每个响应都会延迟,并仍然检查相应索引的值是否正确:

tick(100);
expect(values[0]).toEqual(12);
expect(values[1]).toEqual(15);