Jasmine 测试符合可观察角度2的方法

Jasmine 测试符合可观察角度2的方法,jasmine,angular,rxjs,Jasmine,Angular,Rxjs,我想在Angular 2组件中测试一个方法,该组件订阅了从服务中的方法返回的可观察对象。以下是服务方法的代码摘要: public create(user: User): Observable<any> { return this.http.post(this._api.create, JSON.stringify(user), { headers: this.apiConfig.getApiHeaders() }).map((res: Response

我想在Angular 2组件中测试一个方法,该组件订阅了从服务中的方法返回的可观察对象。以下是服务方法的代码摘要:

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());
  }
这是到目前为止我的规范,但当我尝试窥视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();
    });
  })
);
我想知道是否需要模拟this.\u authentication.create方法来返回一个新的可观察对象,其中包含模拟响应

经过更多的研究,有几篇文章指出我确实需要模拟服务并返回一个同步运行的Observable.of()来解决这个问题,我将复制下面的代码。然而,这仍然不起作用,我已经工作了一天的大部分时间,我觉得这不应该是那么难,任何帮助感谢

class MockAuthentication extends Authentication {
  public create(user: Object): Observable<any> {
    return Observable.of({'test': 'test'});
  }
}
class-MockAuthentication扩展了身份验证{
公共创建(用户:对象):可观察{
返回({'test':'test'})的可观测值;
}
}

我想你应该在你的组件中注入一个mock
路由器
实例,然后在mock
路由器上调用
导航(['/Home'])
后,你检查是否调用了
本地存储。setItem(…)

好吧,我花了一天的大部分时间,但我终于破解了它。与使用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']);
}));
希望这能对将来的人有所帮助

基本上你可以在这里做几件事。首先,用您想要的令牌(或其他响应)的简单可观察响应来存根您的http调用(我猜是从服务中)

service.stub.ts

export class MyStub {
  public create(user: User): Observable<User> {
    return Observable.of('insert test token here');
  }
// other stubbed methods ...
}
导出类MyStub{
公共创建(用户:用户):可观察{
返回可观察的('在此处插入测试标记');
}
//其他存根方法。。。
}
然后在测试中:

mycop.spec.ts

let comp: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let sst: ServiceStub;
describe('MyComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MyComponent],
      schemas: [NO_ERRORS_SCHEMA]
    }).overrideComponent(OnboardFacilityNewComponent, {
      set: {
        providers: [
          { provide: MyService, useClass: ServiceStub },
        ]
      }
    })
    .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(MyComponent);
        comp = fixture.componentInstance;
        st = fixture.debugElement.injector.get(MyService);
      });
  }));
  it('should submit new onboardFacility', fakeAsync(() => {
    const sst = spyOn(sst, 'create').and.returnValue(
      Observable.of('some token here')
    );
    comp.onSubmit(testUser);
    fixture.detectChanges();
    expect(comp.token).toEqual('some token here');
    expect(spy.calls.any()).toEqual(true);
  }));
});
let comp:MyComponent;
let夹具:组件夹具;
让sst:ServiceStub;
描述('MyComponent',()=>{
beforeach(异步(()=>{
TestBed.configureTestingModule({
声明:[MyComponent],
架构:[无错误\u架构]
}).覆盖组件(车载设备NewComponent{
设置:{
供应商:[
{provide:MyService,useClass:ServiceStub},
]
}
})
.compileComponents()
.然后(()=>{
fixture=TestBed.createComponent(MyComponent);
comp=夹具。组件状态;
st=fixture.debugElement.injector.get(MyService);
});
}));
它('应提交新的车载设备',fakeAsync(()=>{
const sst=spyOn(sst,'create')。和.returnValue(
可观察的('此处的某个标记')
);
提交公司(测试用户);
fixture.detectChanges();
expect(comp.token).toEqual(这里是一些token);
expect(spy.calls.any()).toEqual(true);
}));
});
在这里,您可以简单地用测试数据替换实际数据来测试测试的行为,而不是测试床、服务、本地存储等。显然,我在这里编写的测试假设您将从服务返回的令牌存储在组件中,而不是本地存储中,但我只是简单地展示概念,而不是您的特定用例


在您的用例中,您还需要在路由器上设置存根,您可以学习如何执行

由于订阅,在它们被调用之前,感觉会进行检查,但我对可观察对象不熟悉。此外,我们过去在Angular 1中只使用spyOn(localStorage,'setItem'),但我很难弄清楚如何在Angular 2中使用spyOn。我的缺点是,看起来您仍然使用spyOn,我的问题是我无法弄清楚您需要从何处导入“spyOn”,但似乎您已经拥有了它。但我关于之前发生的支票的陈述似乎仍然成立。我已经更新了我的问题以包含规范。这毫无意义。。你为什么在模拟服务中呼叫spyOn?如果它是模拟的,它也返回一个模拟值,您不需要使用returnValue Jasmine函数返回另一个模拟值。@EliasGarcia,因为您正在确定函数逻辑是否调用依赖项。间谍是可选的。
let comp: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let sst: ServiceStub;
describe('MyComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MyComponent],
      schemas: [NO_ERRORS_SCHEMA]
    }).overrideComponent(OnboardFacilityNewComponent, {
      set: {
        providers: [
          { provide: MyService, useClass: ServiceStub },
        ]
      }
    })
    .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(MyComponent);
        comp = fixture.componentInstance;
        st = fixture.debugElement.injector.get(MyService);
      });
  }));
  it('should submit new onboardFacility', fakeAsync(() => {
    const sst = spyOn(sst, 'create').and.returnValue(
      Observable.of('some token here')
    );
    comp.onSubmit(testUser);
    fixture.detectChanges();
    expect(comp.token).toEqual('some token here');
    expect(spy.calls.any()).toEqual(true);
  }));
});