Jasmine 间谍没有覆盖模拟实现

Jasmine spy is not overwriting mock implementation

在我正在测试的 class 的 ngOnInit 方法中,我调用了一个重新运行可观察对象的服务函数。我已经为该服务实现了一个模拟,但我正在尝试为这个确切的测试用例使用一个间谍。 据我所知,除非我在间谍上调用“.and.callThrough()”,否则间谍会覆盖模拟实现。问题是,尽管我为函数设置了一个间谍,但每次模拟实现仍然被执行。

我尝试将间谍移动到 beforeEach 部分,但没有帮助。 我还尝试使用没有“.and.callFake()”扩展名的间谍。但是没有用。

spec.ts 文件:

fdescribe('AppComponent', () => {
  let fixture;
  let component;
  let dataServiceMock: DataServiceMock;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      declarations: [AppComponent],
      providers: [{ provide: DataService, useClass: DataServiceMock }],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    dataServiceMock = TestBed.get(DataService);
  });


  fit('should not show navigation if not logged in', async(() => {
   spyOn(dataServiceMock,'getCurrentUser').and.callFake(() => {
     console.log('IN CALL FAKE')
     throwError(new Error('induced error'))
   });
 }));

服务模拟的实现:

export class DataServiceMock {
  currentUser: User;

  private createValidUser() {
    let validUser = new User();
    validUser.username = 'valid';
    validUser.password = 'valid';
    validUser.role = 'valid';
    this.currentUser = validUser;
  }

  public getCurrentUser(): Observable<User> {
    this.createValidUser();
    return of(this.currentUser);
  }

被测试组件的ngOnInit:

ngOnInit(): void {
  this.dataService.getCurrentUser().subscribe(user => {
    this.currentUser = user;
    console.log('received user:', this.currentUser)
  })
}

我希望控制台日志打印出 "IN CALL FAKE" 并抛出 "induced error" 但控制台打印出 "received user:" 和在服务模拟中创建的 validUser。

这只是一个时间问题。在您的 beforeEach() 中,您正在执行 fixture.detectChanges()。这执行ngOnInit(),详见docs。所以解决方案是不要在那里调用 fixture.detectChanges(),而是在将 return 从 getCurrentUser.

更改后将其移至规范中

这是一个工作 StackBlitz 显示此测试有效。我还更改了更多细节以获得工作测试:

  • 你的 callFake 实际上没有 returning 任何东西。看起来你的意思是 return throwError(),但是这导致了进一步的问题,因为你的组件中实际上没有任何 Observable 错误处理,所以测试它没有意义。
  • 我添加了一个假的 return return of({username: 'test'}) 只是为了让 .subscribe() 在你的组件的 ngOnInit() 中设置一些可以测试的东西 - 然后我设置了一个简单的期望测试 component.currentUser.username 是否设置正确。
  • 我删除了围绕此规范的不必要的 async() 包装器 - 因为您正在使用同步 Observables(使用 of() 创建)进行测试,所以不需要这个。

这是 StackBlitz 的新规范:

it('should not show navigation if not logged in', () => {
  spyOn(dataServiceMock,'getCurrentUser').and.callFake(() => {
    console.log('IN CALL FAKE')
    //  throwError(new Error('induced error'))
    return of({username: 'test'})
  });
  fixture.detectChanges();
  expect(component.currentUser.username).toEqual('test');
});

希望对您有所帮助。