Angular2单元测试使用MdlSnackbarService的组件

时间:2017-03-22 20:20:50

标签: unit-testing angular angular2-testing

我有以下组件:

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);
        });
    }

  }

}

我正在尝试为此设置一些单元测试,但经过几个小时后,我仍然无法运行最简单的测试(由角度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? 我不知道如何修复。我没有找到任何与单元测试有关的答案。

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

1 个答案:

答案 0 :(得分: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中添加该组件,就像您需要的任何其他组件一样。如果您不想这样做,只需通过使用相同的选择器创建一个虚拟组件来模拟该组件,并将组件添加到declarations