View on GitHub

Codeception.docs.ja

Codeception docs japanese translation

Download this project as a .zip file Download this project as a tar.gz file

受け入れテスト

受け入れテストは、技術者ではない人でも実行することができます。技術者ではないテスターやマネージャー、あるいはクライアントでも実行できます。 あなたがウェブアプリケーションを開発している場合、(おそらくあなた自身である)テスターは、あなたのサイトが正しく動いているかをチェックするのにウェブブラウザー以外に必要なものはありません。 シナリオでAcceptanceTesterクラスの行動を再現することによって、サイトを変更する度にそれらを自動的に実行することができます。 AcceptanceTesterの言葉から記録されたかのようCodeceptionは、テストを簡潔に保ってくれます。

CMSやフレームワークをアプリケーションに取り入れていても違いはありません。Java、.NETなど異なるプラットフォームでさえ同じようにテストできます。 どんな時でも、あなたのウェブサイトにテストを加えるということは良い考えだと言えるでしょう。 少なくとも、最後の変更からアプリケーションがしっかりと機能していることに確信が持てるでしょう。

サンプルシナリオ

おそらく、最初に実行したいテストはサインインする機能でしょう。そのようなテストを書くためには、基本的なPHPとHTMLの知識が必要です。

<?php
$I->amOnPage('/login');
$I->fillField('username', 'davert');
$I->fillField('password', 'qwerty');
$I->click('LOGIN');
$I->see('Welcome, Davert!');

このシナリオテストはシンプルなPHP BrowserでもSelenium WebDriverを使ったブラウザーでも実行することができます。 まずはPHP Browserで受け入れテストを書いて行きましょう。

PHP Browser

実際に動くブラウザーが必要となるまでは、これは最も速く受け入れテストを実行する方法です。 リクエストを送り、それからレスポンスを受け取って解析する、というようなブラウザーのような動きをするPHP web scraperを使用しています。 CodeceptionはGuzzleとSymfony BrowserKitをHTMLページを操作するのに使用しています。 HTMLのある要素の実際の可視性や、javascriptの動作をテストできないことに注意してください。 PHP Browserの利点は、PHPとcURLだけでどんな環境でも実行できることです。

一般的なPHP Browserの欠点:

  • 有効なURLのリンクとフォームの送信ボタンしかクリックできないこと
  • フォームの中にないフィールドには書き込めないこと
  • JavaScriptによる動作は機能しないこと:モーダルを表示させたり、datepickersの使用など

テストを書き始める前に、アプリケーションが動作しているホストをローカルコピーしてください。 受け入れテストスイートの設定ファイル(tests/acceptance.suite.yml)に、urlパラメーターを指定する必要があるからです。

class_name: AcceptanceTester
modules:
    enabled:
        - PhpBrowser:
            url: 
        - \Helper\Acceptance

それでは、tests/acceptanceディレクトリーに'Cept'ファイルを作成してください。ファイル名はSigninCept.phpとします。 最初の行に以下のように書きます。

<?php
$I = new AcceptanceTester($scenario);
$I->wantTo('sign in');

この $Iオブジェクトは、すべての動作を記述するために使われます。$IオブジェクトのメソッドはPhpBrowserモジュールから取得されています。 簡単にそれを説明します:

<?php
$I->amOnPage('/login');

amhaveからはじまるすべてのアクションは、初期状態を記述することを想定しています。amOnPageアクションはテストが/loginページから始まることを設定しています。

PhpBrowserを使って、リンクをクリックしたり、フォームに入力することができます。これらは、最も良く使われるアクションだと思います。

クリック

有効なリンクのクリックをエミュレートします。 "href"属性の値のページが開きます。リンク名やCSSセレクター、XPathでクリックするリンクを指定できます。

<?php
$I->click('Log in');
// CSSセレクターを使用する場合
$I->click('#login a');
// XPathを使用する場合
$I->click('//a[@id=login]');
// 第二引数としてコンテキストを使用する場合
$I->click('Login', '.nav');

Codeceptionは、テキストやname属性、CSSセレクター、XPathのどれかで要素を検索しようとします。 locatorの種類を配列として渡すことで、指定することもできます。私たちはstrict locatorと呼んでいます。 利用できるstrict locatorの種類は以下です:

  • id
  • name
  • css
  • xpath
  • link
  • class
<?php
// locatorの種類で指定する場合
$I->click(['link' => 'Login']);
$I->click(['class' => 'btn']);

複雑はXPathロケーターを生成する際に便利なCodeception\Util\Locatorという特別なクラスがあります。たとえば次のように、テーブルの最終行にある要素のクリックを簡単に行えます:

$I->click('Edit' , \Codeception\Util\Locator::elementAt('//table/tr', -1));

フォーム

ウェブサイトのテストにおいて最も時間が取られることは、リンクをクリックすることではないです。もし、リンクだけで構成されているサイトならテストを自動化する必要は無いでしょう。 最も時間を消費する機能はフォームです。Codeceptionはフォームを処理する方法をいくつか提供します。

それでは、Codeceptionのテストでフォームを送信してみましょう。

<form method="post" action="/update" id="update_form">
     <label for="user_name">Name</label>
     <input type="text" name="user[name]" id="user_name" />
     <label for="user_email">Email</label>
     <input type="text" name="user[email]" id="user_email" />
     <label for="user_gender">Gender</label>
     <select id="user_gender" name="user[gender]">
          <option value="m">Male</option>
          <option value="f">Female</option>
     </select>
     <input type="submit" name="submitButton" value="Update" />
</form>

ユーザーからの視点で見ると、このフォームは埋める必要のある複数の項目から構成されており、最後にはUpdateボタンがクリックされます。

<?php
// user_name項目に対応するラベルを使います
$I->fillField('Name', 'Miles');
// inputタグのname属性やid属性を使用しています
$I->fillField('user[email]','miles@davis.com');
$I->selectOption('Gender','Male');
$I->click('Update');

それぞれのフィールドをラベルで検索するためには、labelタグにfor属性を書く必要があります。

開発者から見ると、フォームを送信することは、サーバーに有効なPOSTリクエストを送信しているだけです。 時には、一度にすべての項目に書き込み、'Submit'ボタンをクリックすることなく送信してしまう方が楽です。そのようなシナリオをたった1つのメソッドで書き換えることができます。

<?php
$I->submitForm('#update_form', array('user' => array(
     'name' => 'Miles',
     'email' => 'Davis',
     'gender' => 'm'
)));

submitFormメソッドはユーザーの行動をエミュレートしてはいませんが、フォームが適切にフォーマットされていない時に、非常に有効です。 たとえば、ラベルがついていなかったり、不適切なname属性やid属性がつけられているフォームやjavascriptによって送信されているフォームです。

デフォルトでは、submitFormメソッドはボタンの値を送信することはありません。どのボタンのvalueを送信するかは最後の引数に指定できますし、あるいは第二引数に含めて指定することもできます。

<?php
$I->submitForm('#update_form', array('user' => array(
     'name' => 'Miles',
     'email' => 'Davis',
     'gender' => 'm'
)), 'submitButton');
// これは同じ機能を果たしますが、送信ボタンのvalueは指定する必要があります
$I->submitForm('#update_form', array('user' => array(
     'name' => 'Miles',
     'email' => 'Davis',
     'gender' => 'm',
     'submitButton' => 'Update'
)));

アサーション

PHP browserでは、ページの内容をテストできます。ほとんどの場合は、ページに必要なテキストや要素が存在しているかチェックする必要があるのみでしょう。

そのために最も使い勝手の良いメソッドはseeです。

<?php
// 'Thank you, Miles'というテキストがページにあることをチェックします
$I->see('Thank you, Miles');
// 'Thank you Miles'の内部をチェックします
// この要素は'notice'というクラス属性を持っています
$I->see('Thank you, Miles', '.notice');
// XPathを使用することもできます
$I->see('Thank you, Miles', "//table/tr[2]");
// このメッセージがページに無いことをチェックしています
$I->dontSee('Form is filled incorrectly');

特定の要素がページに存在する(あるいは存在しない)ことをチェックできます。

<?php
$I->seeElement('.notice');
$I->dontSeeElement('.error');

私達は、他にもチェックを実行するために役立つメソッドを用意しています。それらがすべてseeというプレフィックスから始まっていることに注目してください。

<?php
$I->seeInCurrentUrl('/user/miles');
$I->seeCheckboxIsChecked('#agree');
$I->seeInField('user[name]', 'Miles');
$I->seeLink('Login');

条件付きアサーション

時にはアサーションが失敗したとしても、途中でテストを止めたくないでしょう。時間のかかるテストを行っていて、最後まで実行したいかもしれません。 この場合には、条件付のアサーションを使用することができます。seeメソッドはcanSeeメソッドに対応しており、dontSeeメソッドはcantSeeメソッドに対応しています。

<?php
$I->canSeeInCurrentUrl('/user/miles');
$I->canSeeCheckboxIsChecked('#agree');
$I->cantSeeInField('user[name]', 'Miles');

それぞれの失敗したアサーションはテスト結果に示されますが、アサーションが失敗することでテストが止まることは無いでしょう。

コメント

長いシナリオにおいては、どのアクションを実行しようとしていて、その結果何を期待しているのか、説明するべきです。 amGoingToexpectexpectToといったコマンドはテストをよりわかりやすくするために役立ちます。

<?php
$I->amGoingTo('submit user form with invalid values');
$I->fillField('user[email]', 'miles');
$I->click('Update');
$I->expect('the form is not submitted');
$I->see('Form is filled incorrectly');

グラバー

これらのメソッドはテストで使われるデータを取得します。あなたのサイトがすべてのユーザーごとにパスワードを発行指定、そのパスワードでユーザーがサイトにログインできることをチェックしたいという場面を想像してください。

<?php
$I->fillField('email', 'miles@davis.com')
$I->click('Generate Password');
$password = $I->grabTextFrom('#password');
$I->click('Login');
$I->fillField('email', 'miles@davis.com');
$I->fillField('password', $password);
$I->click('Log in!');

グラバーは現在のページから1つの値を取得できるメソッドです。

<?php
$token = $I->grabTextFrom('.token');
$password = $I->grabTextFrom("descendant::input/descendant::*[@id = 'password']");
$api_key = $I->grabValueFrom('input[name=api]');

クッキー、URL、タイトル、その他

クッキーを扱うためのメソッド:

<?php
$I->setCookie('auth', '123345');
$I->grabCookie('auth');
$I->seeCookie('auth');

ページのタイトルを扱うためのメソッド:

<?php
$I->seeInTitle('Login');
$I->dontSeeInTitle('Register');

URLを扱うためのメソッド:

<?php
$I->seeCurrentUrlEquals('/login');
$I->seeCurrentUrlMatches('~$/users/(\d+)~');
$I->seeInCurrentUrl('user/1');
$user_id = $I->grabFromCurrentUrl('~$/user/(\d+)/~');

Selenium WebDriver

Codeceptionのすばらしい特徴は、ほとんどのシナリオが異なるテスト動作環境に容易に移植できることです。 これまでに書いてきたPhpBrowserテストはSelenium WebDriverを使って、実際のブラウザーの中で(あるいはPhantomJSで)実行できます。

ただ1つだけ変更しなければならない事は、AcceptanceTesterクラスがPhpBrowserの代わりにWebDriverを使用するように設定してビルドし直すことです。

acceptance.suite.ymlファイルを変更してください:

class_name: AcceptanceTester
modules:
    enabled:
        - WebDriver:
            url: 
            browser: firefox
        - \Helper\Acceptance

Seleniumでテストを実行するために、Selenium Serverをダウンロードして、起動しておく必要があります。(替わりにghostdriverモードで動くヘッドレスブラウザーのPhantomJSを使うこともできます。)

Seleniumを使用して受け入れテストを実行するならば、Firefoxから始められます。ブラウザーエンジンを使用する事ですべての処理がステップ実行されます。

この場合、seeElementメソッドはページにその要素が存在する事だけをチェックするのではなく、実際のユーザーからの可視性もチェックします。

<?php
$I->seeElement('#modal');

Wait

ウェブアプリケーションをテストしている間に、JavaScriptのeventが起こるまで待機しておく必要があるかもしれません。 複雑なJavaScriptの処理は、その非同期性によってテストが困難になります。テストが先に進んでしまう前に、そのページで起こると予測しているeventを指定できるように、waitメソッドが必要なのです。

例:

<?php
$I->waitForElement('#agree_button', 30); // secs
$I->click('#agree_button');

この場合には、agree buttonが表示されるまで待機し、表示されたらクリックします。30秒経過しても表示されなかったときは、テストは失敗します。他にも使えるwaitメソッドがあります。

詳細なリファレンスはCodeceptionの WebDriverモジュールのドキュメントを参照してください。

複数セッションのテスト

Codeceptionは同時に複数のセッションを実行できます。サイト上でユーザー同士がリアルタイムにメッセージをやり取りする場合が最もわかりやすいです。そのためには2つのブラウザーウィンドウを同じテスト中に同時に立ち上げる必要があるでしょう。CodeceptionはこのためのFriendsと呼ばれるとってもスマートな方法が用意されています。

<?php
$I->amOnPage('/messages');
$nick = $I->haveFriend('nick');
$nick->does(function(AcceptanceTester $I) {
    $I->amOnPage('/messages/new');
    $I->fillField('body', 'Hello all!')
    $I->click('Send');
    $I->see('Hello all!', '.message');
});
$I->wait(3);
$I->see('Hello all!', '.message');

この場合には、2つ目のウィンドウでfriendオブジェクトがdoesメソッドを使用していくつかの行動をしました。

テストが終了する前にウェブページを閉じたい場合、leave()を使ってください。また、friendオブジェクトのロールを指定することもできます:

<?php

$nickAdmin = $I->haveFriend('nickAdmin', adminStep::class);
$nickAdmin->does(function(adminStep $I) {
    // Admin does ...
});
$nickAdmin->leave();

クラウドテスティング

Selenium WebDriverは、テストを異なるプラットフォーム上の実際のブラウザー内で実行することができます。ただ、環境によっては再現が難しいものもあり、特にWindows XPがインストールされた環境が手元にない場合、Windows XP上のインターネットエクスプローラー6~8を使ったテストは困難です。クラウドテスティングサービスが便利なのはこのような点においてです。SauceLabsBrowserStackその他のサービスは、オンデマンドでSelenium Serverや必要となるブラウザーがセットアップされた仮想マシンを作成することができます。テストはクラウドのリモートマシン上で実行され、ローカルファイルへのアクセスはクラウドテスティングサービスが提供する Tunnel と呼ばれる特別なアプリケーションによって行われます。Tunnelはセキュリティーで保護されたプロトコル上で動作し、クラウドで実行されるブラウザーは、ローカルウェブサーバーに接続することができます。

クラウドテスティングサービスは標準的なWebDriverプロトコルで動作するため、その設定は非常に簡単です。WebDriverモジュールの設定を行うだけです:

  • 接続先ホストの指定(クラウドサービスに依存)
  • 認証情報(あなたのアカウントを使ってください)
  • ブラウザー
  • OS

認証情報はparams を使って設定することを推奨しています。

注意点として、クラウドテスティングサービスは無料ではありません。料金体系を調査して、あなたのニーズにあったものを選定してください。また、ローカルサーバーとクラウド間のping値が高すぎる場合には動作が非常に遅くなるため、受け入れテストのランダムな失敗を引き起こします。

AngularJSのテスト

モダンなSPAでは、サーバーに代わりブラウザーがユーザーインターフェースを作成します。伝統的なウェブアプリケーションとは異なり、ユーザーの操作によってウェブページは再読み込みされません。すべてのサーバーとのやり取りは非同期通信を用いたjavascript内で完結します。しかしながら、SPAのテストは困難な作業になる可能性があります。「描画が完了したかどうか」のような、アプリケーションの状態に関する情報が何もない可能性があります。このようなケースでできることとしては、wait* メソッドを多用することや、javascriptを実行してアプリケーションの状態をチェックすることです。

AngularJSのバージョン1.xで構築されたアプリケーション向けに、(Angularアプリの公式テスティングツールである)ProtactorをベースとしたAngularJSモジュールを実装しました。内部的には、前のアクションが完了する前にステップの実行を一時停止し、AngularJS APIを利用してアプリケーションの状態をチェックする、ということを行っています。

AngularJSモジュールはWebDriverを継承していますので、WebDriverのすべての設定オプションを利用可能です。

クリーンアップ

テストをしている中で、あなたの行動はサイト上のデータを変えてしまうかもしれません。2度同じデータを生成したり、アップデートしようとしてテストは失敗する事になるでしょう。この問題を避けるために、データベースはそれぞれのテストごとに再構築する必要があります。CodeceptionはそのためにDbモジュールを提供しています。テストを通過した後にデータベースのdumpをロードします。データベースの再構築を機能させるためには、データベースをdumpしてsqlファイルを作成し、/tests/_dataディレクトリーに配置してください。Codeceptionのglobalの設定にデータベースへの接続情報とパスをセットしてください。

# in codeception.yml:
modules:
    config:
        Db:
            dsn: '[set pdo dsn here]'
            user: '[set user]'
            password: '[set password]'
            dump: tests/_data/dump.sql

Dbモジュールを設定した後は、acceptance.suite.yml設定ファイルにてモジュールを有効化してください。

デバッグ

Codeceptionモジュールは実行中に価値のある情報を出力できます。実行中の詳細を見るために--debugオプションをテスト起動時に付けるだけです。出力をカスタマイズするにはcodecept_debugファンクションを使います。

<?php
codecept_debug($I->grabTextFrom('#name'));

テストの失敗ごとに、最後に表示されていたページのスナップショットをtests/_outputディレクトリーに保存します。PhpBrowserはHTMLのコードを保存し、WebDriverはページのスクリーンショットを保存します。

テストによって開かれたウェブページを調査したくなるときがあると思います。そのような場合にはWebDriverモジュールのpauseExecutionメソッドを利用することができます。

Recorder extensionを利用することにより、テストをステップごとに記録し、実行の様子をスライドショー形式で確認することもできます。

まとめ

CodeceptionとPhpBrowserで受け入れテストを書くことは、良いスタートです。フレームワークで作られたサイトと同じように、Joomla、Drupal、WordPressのサイトも簡単にテストできます。受け入れテストを書くことはPHPでのテスターの行動を説明するようなものです。可読性に長け、とても書きやすいです。テストを実行するごとにデータベースの再構築を忘れないように。