【问题标题】:Angular2 unit testing a component that uses MdlSnackbarServiceAngular2 单元测试使用 MdlSnackbarService 的组件
【发布时间】:2017-03-22 20:20:50
【问题描述】:

我有以下组件:

import { Component, OnInit } from '@angular/core';
import {FormBuilder, FormGroup, FormControl, Validators} from "@angular/forms";
import {ValidationService} from "../../services/validation.service";
import {Router} from "@angular/router";
import {UsersService} from "../../services/users.service";
import {MdlSnackbarService} from "angular2-mdl";

@Component({
  selector: 'app-signup',
  templateUrl: 'signup.component.html',
  styleUrls: ['signup.component.css'],
  providers: [UsersService]
})
export class SignupComponent implements OnInit {

  form: FormGroup;

  constructor(private fb: FormBuilder,
              private router: Router,
              private usersService: UsersService,
              private mdlSnackbarService: MdlSnackbarService) {
    this.form = fb.group({
      "email": new FormControl("", [Validators.required, ValidationService.emailValidator]),
      "password": new FormControl("", Validators.required)
    });
  }

  ngOnInit() {
  }

  onSignup() {
    if (this.form.valid) {
      let email = this.form.value.email;
      let password = this.form.value.password;
      this.usersService.signup(email, password)
        .then(() => {
          this.router.navigate(['/app/home']);
        })
        .catch(err => {
          this.mdlSnackbarService.showToast(err);
        });
    }

  }

}

我正在尝试为此设置一些单元测试,但几个小时后我仍然无法运行最简单的测试(由 angular CLI 自动生成的测试):

fdescribe('SignupComponent', () => {
  let component: SignupComponent;
  let fixture: ComponentFixture<SignupComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ SignupComponent ],
      providers: [UsersService, AngularFire, MdlDialogOutletService],
      imports: [
        AngularFireModule.initializeApp(firebaseConfig),
        ReactiveFormsModule,
        CommonModule,
        RouterTestingModule.withRoutes([
          // { path: 'settings/:collection/edit/:item', component: DummyComponent }
        ])
      ]
    })
    .compileComponents();
  }));

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

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

我收到以下错误:No provider for MdlSnackbarService! 所以我所做的是将MdlSnackbarService 添加到提供程序configureTestingModule

providers: [UsersService, AngularFire, MdlDialogOutletService, MdlSnackbarService]

但是,我得到的错误是Error: No component factory found for MdlSnackbarComponent. Did you add it to @NgModule.entryComponents? 我不知道如何解决。我还没有找到任何与单元测试相关的答案。

有谁知道如何解决这个问题?

【问题讨论】:

    标签: unit-testing angular angular2-testing


    【解决方案1】:

    您应该为所有这些服务使用模拟,即RouterUserServiceMdlSnackbarService。您希望能够控制这些服务在测试期间执行的操作。您并不真正关心服务本身的作用。重要的是组件如何与它们交互。这就是您要测试的内容。

    要设置模拟,您可以执行以下操作

    let router;
    let userService;
    let snackbar;
    
    beforeEach(() => {
       router = { navigate: jasmine.createSpy('navigate') };
       snackbar = { showToast: jasmine.createSpy('showToast') };
       userService = { signup: (email, pass) => null };
    
       TestBed.configureTestingModule({
         providers: [
           { provide: Router, useValue: router },
           { provide: UserService, useValue: userService },
           { provide: MdlSnackbarService, useValue: snackbar }
         ]
       });;
    });
    

    现在在您的测试中,您可以控制UserService 的作用,即返回一个成功的承诺,或返回一个错误的承诺。通过这种方式,您可以测试组件对这两种情况的反应。

    it('should navigate on success', async(() => {
      spyOn(userService, 'signup').and.returnValue(Promise.resolve());
    
      component.signup();
    
      fixture.whenStable().then(() => {
        expect(router.navigate).toHaveBeenCalledWith(['/app/home']);
      })
    }))
    
    it('should show toast on error', async(() => {
      spyOn(userService, 'signup').and.returnValue(Promise.reject('error'));
    
      component.signup();
    
      fixture.whenStable().then(() => {
        expect(snackbar.showToast).toHaveBeenCalledWith('error');
      })
    }))
    

    这基本上就是您想要测试组件以及它如何与这些服务交互的方式。

    至于错误Error: No component factory found for MdlSnackbarComponent.,您需要将该组件添加到测试平台declarations 中,就像添加您需要的任何其他组件一样。如果您不想这样做,只需通过使用相同的选择器制作一个虚拟组件来模拟该组件,并将 that 组件添加到 declarations

    【讨论】:

    • 很好的答案,谢谢!唯一的问题是,路由器模拟仍然不起作用。我遇到了这个错误:Can't bind to 'routerLink' since it isn't a known property of 'a'. 所以我保留了关于路由器的信息:RouterTestingModule.withRoutes(...)
    猜你喜欢
    • 2016-10-19
    • 1970-01-01
    • 2017-09-15
    • 2016-10-20
    • 1970-01-01
    • 2017-10-15
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    相关资源
    最近更新 更多