测试订阅了一个可观察的方法 - Angular 2

Hom*_*rew 8 jasmine rxjs angular

我想测试一个Angular 2组件内部的方法,该组件订阅了从服务中的方法返回的observable.以下是摘要中服务方法的代码:

public create(user: User): Observable<any> {
  return this.http.post(this._api.create,
    JSON.stringify(user), {
      headers: this.apiConfig.getApiHeaders()
    }).map((res: Response) => res.json());
  }
Run Code Online (Sandbox Code Playgroud)

单元测试这个方法很容易,因为它返回一个observable,所以我可以订阅它.但是我想测试已经订阅了这个的组件中的方法:

public onSubmit(user: User): void {
  this._authentication.create(user).subscribe((token) => {
    localStorage.setItem('token', token);
    this.router.navigate(['/Home']);
  });
}
Run Code Online (Sandbox Code Playgroud)

到目前为止我的规格是什么,但是当我试图窥探localStorage.setItem时,它回来时没有被调用.我的理解是它可能会检查它是否在实际被调用之前被调用过.

it('Should login a user and on success store a token in localStorage',
  injectAsync([TestComponentBuilder], (tcb) => {
    return tcb.createAsync(Login).then((fixture) => {
      let instance = fixture.debugElement.componentInstance;
      localStorage.clear();
      spyOn(localStorage, 'setItem');
      instance.onSubmit({userId: 'some@email.com', password: 'password', siteName: 'sample'});
      expect(localStorage.setItem).toHaveBeenCalled();
    });
  })
);
Run Code Online (Sandbox Code Playgroud)

我想知道我是否需要模拟this._authentication.create方法来返回一个带有模拟响应的新observable?

经过更多的研究,一些文章指出我确实需要模拟服务并返回一个同步运行以解决问题的Observable.of(),复制下面的代码.然而,这仍然不起作用,我一直在努力这一天,我不觉得这应该是那么难,任何帮助赞赏.

class MockAuthentication extends Authentication {
  public create(user: Object): Observable<any> {
    return Observable.of({'test': 'test'});
  }
}
Run Code Online (Sandbox Code Playgroud)

Hom*_*rew 3

好吧,这花了我大半天的时间,但我终于破解了。我不需要使用injectAsync 和TestComponentBuilder 来设置规范,我只需要使用inject 并注入组件,就像您执行服务一样。这看起来很好,因为我不需要在视图中测试任何内容,例如事件。

这是有效的最终规范:

it('Should set token in localStorage, set the new user, 
and navigate to home page on succesful login', 
  inject([Login], (login) => {
    login.router.config([ { path: '/', name: 'Home', component: Home }]);
    spyOn(localStorage, 'setItem');
    spyOn(login._currentUser, 'set');
    spyOn(login.router, 'navigate');
    login.onSubmit({ userId: 'some@email.com', password: 'password', siteName: 'sample' });
    expect(localStorage.setItem).toHaveBeenCalledWith('token', 'newToken');
    expect(login._currentUser.set).toHaveBeenCalledWith({ 'test': 'one' });
    expect(login.router.navigate).toHaveBeenCalledWith(['/Home']);
}));
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助将来的某人。