.subscribe之前的Angular2测试逻辑

时间:2016-05-21 14:49:23

标签: unit-testing angular rxjs observable angular2-testing

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

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

我正在努力编写一个测试,在调用showSpinner之前检查true属性是否设置为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));

thismockUserService的位置。

我确信我正在嘲笑userService,特别是loginuserService方法,因为我对此组件的其他测试行为正确。

我还尝试从我的间谍返回Observable.of(this).delay(1),然后在我的测试中调用tick(1)。然而,这导致行为不一致,有时我的测试通过,但有时我得到一个错误说:

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

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

1 个答案:

答案 0 :(得分:0)

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

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

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

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

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

HOWEVER 我们需要记得在我们测试login()时在我们的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);
    });
  })));
});