7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Angular コンポーネントのテスト(sample5 / ネストしたコンポーネントのテスト)

Last updated at Posted at 2018-03-24

目次:Angular コンポーネントのテスト


この章では、あるコンポーネントが別のコンポーネントを所有している場合のテストの方法について説明します。

コンポーネントの作成

まずテストを書くためのコンポーネントを作成します。

$ ng generate component sample5

今回はコンポーネントのクラスには手を加えません。

// sample5.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-sample5',
  templateUrl: './sample5.component.html',
  styleUrls: ['./sample5.component.css']
})
export class Sample5Component implements OnInit {

  constructor() { }

  ngOnInit() {
  }
}

ネストしたコンポーネントにするために、前章で作った Sample4Component を埋め込んでみます。

// sample5.component.html

- <p>
-   sample5 works!
- </p>

+ <app-sample4></app-sample4>

そのままではテストが通らない

<app-sample4></app-sample4> を埋め込むと 'app-sample4' is not a known element: というメッセージとともにテストが落ちるはずです。
Sample5Component のテストは Sample4Component を知らないからです。

解決法その1)子コンポーネントの情報をテストに教える

テスト環境でコンパイル対象となるのは declarations に宣言されたコンポーネントなので、ここに Sample4Component を追加します。

// sample5.component.spec.ts

import { Sample5Component } from './sample5.component';
+ import { Sample4Component } from '../sample4/sample4.component';

describe('Sample5Component', () => {
  ...
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        Sample5Component,
+        Sample4Component,
      ],
      ...
});

Sample4Component は LoggerService に依存しています。
ルートモジュールのインジェクタにサービスが登録されているような場合、Sample5Component のテストは LoggerService を見つける事ができずコンパイルが通りません。
そのようなケースではテスト環境のモジュールのインジェクタにサービス登録をする必要があります。

// sample5.component.spec.ts

import { Sample5Component } from './sample5.component';
+ import { LoggerService } from '../logger.service';

describe('Sample5Component', () => {
  ...
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      ...
+      providers: [
+        { provide: LoggerService, useValue: {} },
+      ]
    })
    ...
});

解決法その2)子コンポーネントを無視する

NO_ERRORS_SCHEMA を使用すると Angular はコンパイルできないHTML要素を無視するようになります。
Sample4Component はコンパイル対象外となるため、依存サービスを注入する必要はありません。

参考
NO_ERRORS_SCHEMA は @experimental として定義されているため将来的に変わる可能性があります。
Angular v5.2.8 ng_module.ts
https://github.com/angular/angular/blob/5.2.8/packages/core/src/metadata/ng_module.ts#L42-L49

// sample5.component.spec.ts

+ import { NO_ERRORS_SCHEMA } from '@angular/core';

import { Sample5Component } from './sample5.component';
import { Sample4Component } from '../sample4/sample4.component';

describe('Sample5Component', () => {
  ...
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        Sample5Component,
      ],
+      schemas: [ NO_ERRORS_SCHEMA ],
    })
    .compileComponents();
  }));
  ...
});

解決法その3)子コンポーネントの構造をテスト用に置き換える

解決法その1と同じように、コンパイル対象に Sample4Component を追加します。
依存サービスは TestBed.overrideComponent を利用して、Sample4Component のインジェクタに登録します。

// sample5.component.spec.ts

+ import { LoggerService } from '../logger.service';
import { Sample5Component } from './sample5.component';
+ import { Sample4Component } from '../sample4/sample4.component';

describe('Sample5Component', () => {
  ...
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        Sample5Component,
+        Sample4Component,
      ],
    })
+    .overrideComponent(Sample4Component, {
+      set: {
+        providers: [
+          { provide: LoggerService, useValue: {} },
+        ],
+      },
+    })
    .compileComponents();
  }));
  ...
});

overrideComponent

overrideComponent はコンポーネントのメタデータ(Componentデコレータ)を上書きするメソッドです。
依存の注入以外にもさまざまなカスタマイズを加える事ができます。

使い方

add / remove / set のいずれかのキーを指定して、メタデータに対して行う操作を指定します。

.overrideComponent(FooComponent, {
  set: { ... },
  add: { ... },
  remove: { ... },
})

それぞれの操作に対して、以下のようなキーと値のペアが指定できます。

.overrideComponent(FooComponent, {
  set: {
    selector?: string;
    template?: string;
    templateUrl?: string;
    providers?: any[];
  },
})

「プロパティを表示するだけのテンプレートに置き換える」「ボタンを押したらイベントを発火させる」など、工夫次第でコンポーネント自体をテストダブルのように扱う事ができます。

.overrideComponent(FooComponent, {
  set: {
    template: `
      <h1>{{value}}</h1>
      <button (click)="emit()"></button>
    `,
  }
})

公式ドキュメント The overrideComponent method
https://angular.io/guide/testing#the-overridecomponent-method


次の記事:sample6 / 入出力を伴うコンポーネントのテスト

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?