SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

次世代Webアプリケーションフレームワーク「Angular」の活用

ソフトウェアの品質を高めて作業効率も上げる、Angularの自動単体テスト

次世代Webアプリケーションフレームワーク「Angular」の活用 第13回

  • X ポスト
  • このエントリーをはてなブックマークに追加

コンポーネントの単体テスト

 ロジックだけが含まれるサービスと異なり、コンポーネントはロジックとUIの組み合わせなので、画面の入力や表示を確認したい場合があります。以下では、図1と同じ動作をするサンプル(P003-component)を例に、コンポーネントの単体テストを説明します。

テスト観点と単体テストコード

 テスト対象コンポーネント(AppComponent)は、入力内容をサービス(GreetService)に渡してあいさつ文を取得し、画面に表示します。GreetServiceの単体テストは別に行うので、コンポーネントの単体テストでは「入力内容がGreetServiceに正しく渡せていること」と、「GreetServiceから取得したあいさつ文が正しく画面表示されていること」を確認すれば十分です。この観点で、コンポーネントの単体テストを作っていきます。

 まず、テスト前に実行されるbeforEach部をリスト7に示します。

[リスト7]コンポーネントテストのbeforeEach部(P003-component/src/app/app.component.spec.ts)
beforeEach(() => {
  // GreetServiceのモックを作成 ...(1)
  const mockService = jasmine.createSpyObj('GreetService', ['getGreet']);
  mockService.getGreet.and.callFake(
    (name: string, date: Date, locale: string) => name + ':' + locale
  );
  // TestBedの設定処理 ...(2)
  TestBed.configureTestingModule({
    declarations: [AppComponent],
    imports: [FormsModule],
    providers: [
      // GreetServiceをモックに入れ替え ...(3)
      { provide: GreetService, useValue: mockService }
    ]
  });
});

 (1)は、GreetServiceのモックを作成する処理です。モック変数mockServiceに対してgetGreet.and.callFakeメソッドを利用すると、getGreetメソッドの処理内容を置換できます。ここでは名前とロケールの引数をつないで返却させるように処理を単純化して、コンポーネントの単体テストを行いやすくします。

 (2)で、コンポーネントの動作に必要な設定を行っています。configureTestingModuleメソッドは、app.module.tsの@NgModuleデコレーターと同じ内容を与えて設定できます。ここでは、declarationsにテスト対象コンポーネント(AppComponent)を、importsにはコンポーネントが必要とするフォーム関連モジュールFormsModuleを指定しています。依存性注入の動作を指定するprovidersには、GreetServiceをモックに入れ替えるように記述します(3)。

 実際のテストはリスト8のようになります。

[リスト8]コンポーネントテストの実装(P003-component/src/app/app.component.spec.ts)
it('コンポーネントクラスだけのテスト', () => {
  const fixture = TestBed.createComponent(AppComponent); // ComponentFixtureを取得 ...(1)
  const app = fixture.componentInstance; // コンポーネントを取得 ...(2)
  // コンポーネントのプロパティを設定してクリックメソッドを実行 ...(3)
  app.name = '太郎';
  app.locale = 'ja-JP';
  app.onClickGreet();
  // 実行結果、画面に表示するプロパティの内容を確認 ...(4)
  expect(app.greetText).toEqual('太郎:ja-JP');
});

 (1)のTestBed.createComponentメソッドでComponentFixtureを取得します。ComponentFixtureは、コンポーネントとUI要素の両方にアクセスできるテスト用クラスです。(2)のように、ComponentFixtureのcomponentInstanceプロパティで、コンポーネントの実体にアクセスできます。

 (3)で、画面のテキストボックス内容に対応するプロパティ(name、locale)をコンポーネントに設定後、ボタンクリックに対応したonClickGreetメソッドを実行します。実行後に、あいさつ文の画面表示に対応するプロパティ(greetText)が想定通りの値になっているか確認します(4)。多くの場合、画面要素そのものを参照しなくても、画面要素に対応するプロパティを確認すれば、十分な単体テストができます。

画面要素を直接確認する単体テストコード

 とはいえ、やはりプロパティではなく画面要素を直接確認したい場合もあります。画面要素を確認するテストの例をリスト9に示します。

[リスト9]画面要素を確認するテスト(P003-component/src/app/app.component.spec.ts)
it('画面要素を確認するテスト', () => {
(略:途中まではリスト8と同じ)
  app.onClickGreet();
  // 変更検知を実行して画面を更新 ...(1)
  fixture.detectChanges();
  // 画面のHTML要素から文字列を取得して、内容を確認 ...(2)
  const greetText = fixture.nativeElement.querySelector('#greetText').textContent;
  expect(greetText).toEqual('あいさつ文:太郎:ja-JP');
  });

 onClickGreetメソッドを実行後、まず(1)のfixture.detectChangesメソッドで変更検知を模擬します。単体テストの実行時は、画面の変更検知が自動的に行われないので、明示的に変更検知を実行させます。

 (2)のfixture.nativeElementプロパティは、コンポーネントの画面に対応するオブジェクトです。querySelectorメソッドでCSSセレクターを指定すると、コンポーネントの画面から特定のHTML要素を取得できます。ここでは「#greetText」と指定して、idに「greetText」と指定された要素を取得します。要素のtextContentプロパティを参照して、画面に表示された内容を変数greetTextに取得して、expectメソッドで内容を確認します。

[参考]Angular公式ページの単体テスト関連ドキュメント

 Angularの公式ページでは、PipesやRouterのテスト方法など、単体テストに関するさまざまな内容が説明されています。単体テストについて、より詳細な情報が必要な場合に参照してください。

図6 Angularのテストに関するドキュメント
図6 Angularのテストに関するドキュメント(公式ページより)

まとめ

 本記事では、Angularのプロジェクトで単体テストを行う方法について説明しました。Webページを構成するコンポーネントやサービスを細かく分割して、それぞれに単体テストを設定すれば、部品単位でコードの品質を確保しながら開発を進めることができます。

 次回は、2018年5月にリリースされたAngularのバージョン6について、新機能などを説明していきます。

参考資料

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
次世代Webアプリケーションフレームワーク「Angular」の活用連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト  吉川 英一(ヨシカワ エイイチ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/10838 2018/05/28 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング