一人もくもく会 α verでサービス開始しました。

Angular2でコンポーネントのユニットテストを書いてみた

Angularのコンポーネントユニットテストを書いてみた。 TestBedを使用しているパターン。

angular-cliでファイルを作成しつつ、 アプリケーションをある程度書いてng testしてみると大量にエラーが出るので、 それらをいくつかエラーが出ないように修正してみた。

エラーが出る原因

基本的には、htmlで使用されているコンポーネントや、 ts内で使用されているサービスなどの依存関係が満たされていないため。

アプリケーション実行時はmoduleの設定などで満たされているが、 テストは各テストで別途設定してあげなければならない。

テストは別途設定にすることで、各サービスなどはmockを使用できるようになっている。

テスト例

ユーザー情報を取得して表示するだけのページのコンポーネント例。 コンポーネント側ではActivatedRouteからidを取得し、 UserServiceでそのidからhttpでユーザー情報であるUserを取得し、 Userをコンポーネント上で表示するだけの例。

/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { ActivatedRouteStub } from '../../../../testing/router-stubs';
import { UserServiceStub } from '../../../../testing/user-service-stub';
import { UserDetailComponent } from './user-detail.component';
import { UserService } from '../../../services/user.service';
import { User } from '../../../models/user';

describe('UserDetailComponent', () => {
  let component: UserDetailComponent;
  let fixture: ComponentFixture<UserDetailComponent>;
  let activatedRoute = new ActivatedRouteStub();
  let userService = new UserServiceStub();
  let user = new User();

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ UserDetailComponent ],
      providers: [
        {provide: ActivatedRoute, useValue: activatedRoute},
        {provide: UserService, useValue: userService}
      ],
    })
    .compileComponents();

    activatedRoute.testParams = {id: 1};
    userService.user = user;
  }));

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

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

  it('user set', () => {
    expect(component.user && component.user == user).toBeTruthy();
  });
});

declarations

html上に表示するコンポーネントはここで設定。 他のコンポーネントを使っている場合はここに追記。

providers

サービスなどの設定。provideで実際のクラスを指定し、useValueでモックを指定できる。

モック

router-stubs.tsは下記で書かれたものを改造したりして使用。

Testing - ts - GUIDE

Observableを使用しているのでクラスにまとめた方が使いまわしやすい、ということ。 providersではそれらのモックを使用し、compileComponentでコンポーネントが構築された後、

    activatedRoute.testParams = {id: 1};
    userService.user = user;

で返すべき値をセットしている。 上記はgetメソッドになっているので、セットされるとコールバックが起動されて処理が進んでいく。 あとは自由にitで確認していくだけ。

適当にぱぱっとエラーを消して処理を追加しただけなので全体的に正しいかどうかは不明。