简体   繁体   English

Angular2 / RxJS / Jasmine:如何测试可观察的链/序列(操作员)

[英]Angular2 / RxJS / Jasmine : How to test Observable chain/sequence (operators)

As part of an Angular 4 project, I am desperately trying to test with Jasmine a function which implement an RxJs chain/sequence with operators ( map in my case). 作为Angular 4项目的一部分,我正拼命尝试用Jasmine测试一个功能,该功能通过运算符实现RxJs链/序列(在我的情况下为map )。

class RendezVousResolver {

  searchRendezVous(code: string): Observable<any> {
    return Observable.create(observer => {
      this.userCardService.readCard(code).map(userData => {
        this.rendezVousService.search(userData).subscribe(
          result => {
            observer.next(result);
          },
          error => {
            observer.error(error);
          }
        );
      });
    });
  }

}

My unit test uses 2 mocks in order to "simulate" the 2 services' layers: userCardService and rendezVousService . 我的单元测试使用2个模拟来“模拟”这2个服务的层: userCardServicerendezVousService

class MockUserCardService {

  readCard(code: string): Observable<any> {
    return Observable.of('<data></data>');
  }

}

class MockRendezVousService {

  search(userData : string): Observable<any> {
    return Observable.of({
      rdvs: []
    });
  }

}

beforeEach(() => {
  TestBed.configureTestingModule({
    providers: [
      RendezVousResolver,
      { provide: RendezVousService, useClass: MockRendezVousService },
      { provide: SwcVitaleReadingService, useClass: MockSwcVitaleReadingService }
    ]
  });
  fixture = TestBed.get(RendezVousResolver);
});

And here my unit test. 这是我的单元测试。

it('should return the expected response', async(() => {
  fixture.resolve(undefined, undefined).subscribe(
    rdvs => {
      console.log("expect");
      expect(rdvs).toEqual({
        rdvs: []
      });
    },
    error => {
      console.log("fail");
      fail('No error was expected');
    }
  );
}));

When I execute it, the test seems to not wait for the events emitted by the mocked Observable. 当我执行它时,测试似乎没有等待模拟的Observable发出的事件。 Neither the expected nor the fail are executed. 既不执行expected fail ,也不执行fail I'm sure about that because nothing is logged in the console. 我敢肯定,因为控制台中没有任何记录。

The only way I found to make this test passed is to not use the operator map and replace my code with nested subscriptions. 我发现通过此测试的唯一方法是不使用运算符map而将我的代码替换为嵌套订阅。

searchRendezVous(code: string): Observable<any> {
  return Observable.create(observer => {
    this.userCardService.readCard(code).subscribe(
      userData => {
        this.rendezVousService.search(userData).subscribe(
          rdvs => {
            observer.next(rdvs);
          },
          error => {
            observer.error(error);
          }
        )
      },
      error => {
        observer.error(error);
      }
    );
  });
}

I encountered the same problem with others operators than map ( zip for example). map (例如zip )之外,其他运算符也遇到了相同的问题。

Thank you for your help. 谢谢您的帮助。

You can simplify your RendezVousResolver by swapping Observable.create for existing behaviour / functions in RxJs: 您可以通过将Observable.create交换为RxJs中的现有行为/函数来简化RendezVousResolver

class RendezVousResolver {
  searchRendezVous(code: string): Observable<any> {
    return this.userCardService.readCard(code)
      .mergeMap(userData => this.rendezVousService.search(userData));
  }
}

That way you have less edge cases to catch yourself. 这样,您就可以减少遇到麻烦的情况。

Testing this can be done without time by swapping the readCard and search with mocks returning a Rx.Observable.from([]) with the expected mock data. 这个测试可以不受时间通过交换来完成readCardsearch与嘲笑返回Rx.Observable.from([])与预期的模拟数据。 Simply invoking .toPromise() on your searchRendezVous() will make that work without any scheduler magic. 只需在searchRendezVous() .toPromise()上调用.toPromise()使此工作无需任何调度程序魔术。

it('returns data', () => {
  return searchRendezVous('foo')
    .toPromise()
    .then(searchResults => {
      expect(searchResults).to.not.be.empty();//assert what you need
    })
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM