CodeZine(コードジン)

特集ページ一覧

ブラウザーを自動で操作し動作確認できる、「Angular」のe2eテスト

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

  • LINEで送る
  • このエントリーをはてなブックマークに追加
目次

e2eテストでブラウザーを操作する方法

 リスト2で利用したbrowserやelementを使って、Webブラウザーの操作や結果の取得を行う方法を、図5のサンプル(P002-basic)で説明します。このWebページには、テキストボックス、ボタンと2個のラベルがあり、テキストボックスの入力内容は、データバインディングで上のラベル(メッセージ1)にすぐに反映されます。そのあとでボタンを押すと、下のラベル(メッセージ2)にもテキストボックスの入力内容が反映されます。

図5 e2eテストでテストするサンプルWebページ(P002-basic)
図5 e2eテストでテストするサンプルWebページ(P002-basic)

 このWebページに対するe2eテストのコードはリスト3です。ここでは、Webブラウザーの操作方法が直感的にわかるように、PageObject(app.po.ts)は利用せず、すべてのテスト処理をテストコードに直接記述しています。

[リスト3]図5のWebページに対応するe2eテスト(P002-basic/e2e/src/app.e2e-spec.ts)
import { browser, element, by } from 'protractor'; // インポート ...(1)
describe('P002-basic', () => {
  it('e2eテストの動作確認', () => { // ...(2)
    // URLを指定してWebページを表示 ...(3)
    browser.get('/');
    // ページ内のHTML要素を取得 ...(4)
    const message1 = element(by.css('#message1'));  // CSSを指定できる
    const message2 = element(by.id('message2'));    // IDを直接指定できる
    const textBox1 = element(by.id('textBox1'));
    const button1 = element(by.id('button1'));
    // ページの初期条件 ...(5)
    expect(message1.getText()).toEqual('');
    expect(message2.getText()).toEqual('初期メッセージ');
    // テキストボックスに文字を入力 ...(6)
    textBox1.clear();
    textBox1.sendKeys('テキストボックスに文字を入力');
    // message1はすぐ更新されるが、message2はまだ更新されない ...(7)
    expect(message1.getText()).toEqual('テキストボックスに文字を入力');
    expect(message2.getText()).toEqual('初期メッセージ');
    // ボタンをクリック ...(8)
    button1.click();
    // ボタンクリックで、message2も更新される ...(9)
    expect(message1.getText()).toEqual('テキストボックスに文字を入力');
    expect(message2.getText()).toEqual('テキストボックスに文字を入力');
  });
});

 まず、Protractorがテスト用に提供する変数browser、element、byをインポートします(1)。テストの処理は(2)以降です。

 テストでは、最初に(3)のbrowser.getメソッドに相対URL('/')を指定して、テスト対象のWebページを表示させます。browserはWebブラウザーに関連する操作を行えるオブジェクトです。

 次に(4)で、ページ内のHTML要素を取得します。elementはHTML要素を取得するメソッドで、条件を指定するby.cssメソッド(CSS記述を指定)またはby.idメソッド(HTML要素のIDを指定)と組み合わせて、HTML要素を取得できます。

 (5)では、取得したHTML要素のgetTextメソッドで要素の内容(テキスト)を取得して、想定値と比較しています。

 (6)は、テキストボックスに文字を入力する処理です。テキストボックスの要素に対して、clearメソッドで入力値を削除してから、sendKeysメソッドで文字を入力します。ここでは入力後、(7)でラベルの値を想定値と比較しています。

 (8)のようにclickメソッドを実行すると、その要素をクリックできます。ここではクリック後、(9)でラベルの値を想定値と比較しています。

 このように、Protractorの機能を利用すると、人間が操作するのと同じようにブラウザーを操作して、e2eテストを実行できます。

PageObjectでテストの再利用性を高める

 リスト3では、ページ遷移や要素の取得・操作など、Webページの内容に強く依存する処理を、テストのファイルに直接記述していました。この場合、Webページのレイアウトなどを変更すると、テストの記述も修正する必要があります。

 こういった問題に対して、Webページの内容に強く依存する処理を別のクラスに切り出す「PageObject」と呼ばれる考え方が有効です。Angularのプロジェクトでは、PageObjectのファイルがデフォルトで生成されます。

 図5のWebページに対応するPageObjectは、リスト4のように実装できます。リスト3でテストコードに記述されていたページ遷移やテキストの取得・入力、ボタンのクリックといった処理を実装します。

[リスト4]図5のWebページに対応するPageObject(P003-page-object/e2e/src/app.po.ts)
export class AppPage {
  // ページを表示
  navigateTo() {
    return browser.get('/');
  }
  // メッセージ1を取得
  getMessage1() {
    return element(by.css('#message1')).getText();
  }
  // メッセージ2を取得
  getMessage2() {
    return element(by.id('message2')).getText();
  }
  // テキストボックスに入力
  inputToTextbox(input:string) {
    const textBox1 = element(by.id('textBox1'));
    textBox1.clear();
    textBox1.sendKeys(input);
  }
  // ボタンをクリック
  clickButton1() {
    element(by.id('button1')).click();
  }
}

 このPageObjectを利用すると、リスト3のテストはリスト5のように書き換えられます。

[リスト5]リスト4のPageObjectを利用して記述したe2eテスト(P003-page-object/e2e/src/app.e2e-spec.ts)
describe('P003-page-object', () => {
  let page: AppPage;      // PageObject ...(1)
  beforeEach(() => {
    page = new AppPage(); // PageObjectを初期化 ...(2)
  });
  it('e2eテストの動作確認', () => {
    // ページ遷移
    page.navigateTo();
    // ページの初期条件
    expect(page.getMessage1()).toEqual('');
    expect(page.getMessage2()).toEqual('初期メッセージ');
    // テキストボックスに文字を入力
    page.inputToTextbox('テキストボックスに文字を入力');
    // message1はすぐ更新されるが、message2はまだ更新されない
    expect(page.getMessage1()).toEqual('テキストボックスに文字を入力');
    expect(page.getMessage2()).toEqual('初期メッセージ');
    // ボタンをクリック
    page.clickButton1()
    // ボタンクリックで、message2も更新される
    expect(page.getMessage1()).toEqual('テキストボックスに文字を入力');
    expect(page.getMessage2()).toEqual('テキストボックスに文字を入力');
  });
});

 PageObjectのAppPage(1)を、beforeEachで生成して(2)、テストで利用します。リスト3とリスト5は同じ内容のテストですが、Webページ固有の処理がPageObjectに切り出されていることに注目してください。

 PageObjectを利用すると、Webページの内容に依存する処理をテストのコードから分離できるため、ページのレイアウトの変更があってもPageObjectだけを修正すればよく、テストのコードはそのまま利用できます。また、PageObjectを使いまわして、別のテストを行うこともできます。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

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

もっと読む

著者プロフィール

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

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

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

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5