Jasmine 间谍不会覆盖模拟实现

Cin*_*ode 4 mocking jasmine karma-jasmine angular angular-test

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

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

规格.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'))
   });
 }));
Run Code Online (Sandbox Code Playgroud)

服务模拟的实现:

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);
  }
Run Code Online (Sandbox Code Playgroud)

被测试组件的ngOnInit:

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

我希望控制台日志打印出“IN CALL FAKE”并抛出“诱导错误”,但控制台打印出“received user:”以及在服务模拟中创建的 validUser。

dmc*_*dle 6

这只是一个时间问题。在你的beforeEach()你正在执行fixture.detectChanges()。这会执行ngOnInit(),详细信息请参阅文档。所以解决方案是不要fixture.detectChanges()在那里调用,而是在更改了返回后将其移至规范中getCurrentUser

这是一个正在运行的StackBlitz,显示了此测试的工作情况。我还更改了更多细节以获得工作测试:

  • 您的 callFake 实际上没有返回任何内容。看起来您打算 return throwError(),但这会导致进一步的问题,因为您的组件中实际上没有任何 Observable 错误处理,因此测试它是没有意义的。
  • 我添加了一个假返回,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');
});
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助。