2018-10-02に更新

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は下記で書かれたものを改造したりして使用。

Angular Docs

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

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

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

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


だら@Crieit開発者

Crieitの開発者です。 主にLAMPで開発しているWebエンジニアです(在宅)。大体10年程。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel5, CakePHP3, JavaScript, RoR 趣味:Elixir, Phoenix, Node, Nuxt, Express, Vue等色々

Crieitはαバージョンで開発中です。進捗は公式Twitterアカウントをフォローして確認してください。 興味がある方は是非記事の投稿もお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか
関連記事

コメント