2

我目前正在为我的一个组件编写单元测试。特别是我有login(): void功能。这是简化的逻辑:

login(): void {
  this.showSpinner = true;
  this.userService.login(loginData)
    .subscribe(result => {
      this.showSpinner = false;
    }
  )
}

我正在努力编写一个测试,showSpinnertrue调用userService.login.

这是我的测试:

it('should display the spinner when the form is being saved',
  inject([TestComponentBuilder], fakeAsync((tcb: any) => {
    createComponent(tcb).then((fixture:ComponentFixture<any>) => {
      fixture.componentInstance.login();
      expect(fixture.componentInstance.showSpinner).toBe(true);
      tick();
    });
  })));
});

这个测试失败了,因为.subscribe得到解决/立即运行(我尝试在我的组件中注释掉this.showSpinner = false,并且测试通过了)。

在我的userService模拟中,对于方法模拟,我有以下内容login

this.loginSpy = this.spy('login').andReturn(Observable.of(this));

this在哪里mockUserService

我有信心我正在嘲笑userService,特别是正确的login方法userService,因为我对该组件进行了其他测试,这些测试表现正确。

我也试过Observable.of(this).delay(1)从我的间谍那里回来,然后打电话给tick(1)我的测试。然而,这会导致不一致的行为,因为有时我的测试通过了,但其他时候我收到一条错误消息:

Error: 1 periodic timer(s) still in the queue.

如何测试前面的逻辑.subscribe()

4

1 回答 1

0

经过更多考虑,我意识到我当前的代码不遵守单一职责原则。这个想法来自这样一个事实,每个人都在重复你应该“重构难以测试的代码”。

考虑到这一点,我将在调用之前需要完成的所有逻辑都移到了userService.login它自己的单独函数中。这基本上导致:

login():void {
  this.userService.login(this.loginData)
    .subscribe(result => {
       this.showSpinner = false;
    });
}

formSubmit(): void {
  this.showSpinner = true;
  this.login();
}

这个逻辑现在更容易测试。

但是,我们需要记住在login()测试时在我们的方法上添加一个 spy formSubmit(),就好像我们不这样做一样,formSubmit()只会简单地调用login(),这将再次同步完成,我们将遇到同样的问题。所以我对这个功能的新的和最终的测试是:

it('should display the spinner when the form is being saved',
  inject([TestComponentBuilder], fakeAsync((tcb: any) => {
    createComponent(tcb).then((fixture:ComponentFixture<any>) => {
      var loginSpy = spyOn(fixture.componentInstance, 'login');
      fixture.componentInstance.formSubmit();
      expect(fixture.componentInstance.showSpinner).toBe(true);
    });
  })));
});
于 2016-05-21T20:32:10.760 回答