【问题标题】:Testing Angular component, which changes based on observable service测试 Angular 组件,该组件根据可观察服务进行更改
【发布时间】:2018-01-02 17:22:24
【问题描述】:

我正在尝试测试 Angular 4 中组件的 login() 方法,该方法依赖于返回成功或错误的 Observable authService

被测代码:

login() {
    this.loginError = undefined;
    this.loadingService.present('Logging In...');

    this.authService
      .login(this.form.value)
      .subscribe(
        (currentUser: any) => {
          this.loadingService.dismiss();
          this.navCtrl
            .setRoot('TabsPage')
        },
        (error: any) => {
          this.loadingService.dismiss();
          this.loginError = error._body;
          console.error('LoginPage :: Login Error:', error);
        }
      );
}

我知道要成功地对这个方法进行单元测试,我需要隔离它。我为authService 创建了一个存根,并将其注入TestBed

身份验证存根

export class AuthenticationServiceStub {

  login() {};

  getCurrentUserFromStorage() {};

  logout() {};

};

测试台配置:

TestBed.configureTestingModule({
      declarations: [
        ...components,
      ],
      providers: [
        NavController,
        LoadingService,
        FormBuilder,
        { provide: AuthService, useClass: AuthenticationServiceStub }
      ],
      imports: [
        IonicModule.forRoot(LoginPage),
        PierDataServicesModule.forRoot(),
      ],
    });

据我了解,要对login() 进行单元测试,我必须测试这四件事:

  1. this.loginError 设置为未定义
  2. this.loadingService.present('Logging In...') 被调用
  3. this.authService.login(this.form.value) 被调用
  4. 如果this.authService.login(this.form.value)返回成功,那 成功功能块中的两个方法都被调用,并且如果 错误,错误块中的方法被调用。

这就是我的规范的样子,(我已经成功测试了 1、2、3):

测试:

describe('Login()', () => {

  let fixture:      ComponentFixture<LoginPage>;
  let instance: any = null;
  let authService: any;

  beforeEach(async(() => TestUtils.beforeEachCompiler([LoginPage]).then(compiled => {

    fixture = compiled.fixture;
    instance = compiled.instance;

    spyOn(instance, 'login').and.callThrough();
    spyOn(instance.loadingService, 'present');
    spyOn(instance.authService, 'login').and.returnValue({ subscribe: () => {} });

    instance.login();

  })));

  it("should be callable", async(() => {
    expect(instance.login).toHaveBeenCalled();
  }));

  it("should call loadingService.present ", async(() => {
    expect(instance.loadingService.present).toHaveBeenCalled();
  }));

  it("should call authService.login", async() => {
    expect(instance.authService.login).toHaveBeenCalled();
  });


});

我不知道如何测试 4 号。如何通过成功或错误复制被调用的 Observable,并检查这些函数体中的函数是否运行?

我可以构建模拟 login() 方法并从被测代码中复制功能,但测试模拟方法而不是实际代码似乎真的违反直觉。

我应该使用真正的authService 方法并构建一个模拟后端吗?这是行得通的吗?如果有,怎么做?

我应该使用 Karma 来spyOn 方法并修改它们以执行我想要的操作吗?我想我可以做这样的事情:spyOn(instance.authService, 'login').and.callThrough().and.throwError(),但这种方法没有成功。

【问题讨论】:

  • 你能提供一个plunker吗?

标签: angular unit-testing jasmine observable


【解决方案1】:

单元测试不应该涉及真正的服务,因为这会引入额外的活动部件。

测试 Promise 和 observable 的一种简洁方法是提供一个真实的,而不是模仿它们的对象:

spyOn(instance.authService, 'login').and.returnValue(Observable.of(null));
...
expect(instance.loadingService.dismiss).toHaveBeenCalled();
expect(instance.navCtrl.setRoot).toHaveBeenCalledWith('TabsPage');
expect(instance.lognError).toBe(...);
...
const _body = {};
spyOn(instance.authService, 'login').and.returnValue(Observable.throw({ _body }));
...
expect(instance.loadingService.dismiss).toHaveBeenCalled();
expect(instance.navCtrl.setRoot).not.toHaveBeenCalled();
expect(instance.lognError).toBe(_body);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多