Laravel5.1から、新テスト記述法が導入され、それはそれで素晴らしいのですが、細かいテストを書こうとするとちょっと限界を感じたので、php-webdriverやGuzzleを組み合わせる方法をメモしておきます。
なお、ここでは、php-webdriverやGuzzleをLaravelで使う導入のメモだけなので、php-webdriverやGuzzleの使い方については、下記を参考にしてください。
##5.1のテスト(旧laracast/integrated)の難点
5.1でのテストはちょっとテストを書くにはいいのですが、下記のような問題があります(私の調査不足だけかもしれませんが)。
- JavaScriptを多用したUIのテストは厳しい。
- POST/GETとかでテストだけの記述を覚えないといけない。
- visitで($baseUrlを変更しても)外のサイトをテストできない。
なので、
- UIのテストは中途半端なSelenium使うなら、php-webdriver使った方が手間がない。
- Guzzleを利用すれば、テストだけでなく、普通の開発時もノウハウが共通化できる。
と感じたのでメモするというわけです。
とは言え、Laravel以外で使う場合となんら変わったことはありません。
##composer.jsonの設定
require-devにguzzleとwebdriverの記述(下の2行)を追加し、
"require-dev": {
"fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*",
"phpunit/phpunit": "~4.0",
"phpspec/phpspec": "~2.1",
"guzzlehttp/guzzle": "^6.1",
"facebook/webdriver": "^1.0"
},
composer updateを実行します。
composer update
##テストを書く
Lravelではtests以下にテストを書きます。既に存在しているサンプルのExampleTest.phpを編集すればいいでしょう。
既にテスト対象のサイトやAPIはあるものとして、下記のようなコードを書きます。
あくまで雰囲気だけですが、下記のようなことを行っています。
- UIではChromeを起動して閉じている。
- APIのリクエストはGuzzleで行ない、標準のassertで評価している。
- QueryBuilder(もちろんEloquentでも!)でDBの内容を参照し、assertしている。
標準のテストより記述は少々複雑ですが、制限を気にしる必要がないので気は楽かなと。
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Facebook\WebDriver;
use Facebook\WebDriver\WebDriverExpectedCondition;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\Remote;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
class ExampleTest extends TestCase
{
//UIのテスト
public function testWebUI()
{
//準備(java -jar java -jar selenium-server-standalone-2.48.2.jar済である必要あり)
$host = 'http://localhost:4444/wd/hub';
//chromedriverを指定(chromedriverをダウンロードして/user/local/bin等に入れておく。
$driver = RemoteWebDriver::create($host, DesiredCapabilities::chrome());
// //テストするサイトに移動
$driver->get('http://localhost/test/index.php');
//いろいろな処理(省略)
//閉じる
$driver->close();
}
//APIのテスト
public function testWebAPI_GET()
{
//
$client = new GuzzleHttp\Client();
//get
$res = $client->get('http://localhost/test/api.php',[
'query'=>[
'name'=>'POO',
'email'=>'poo@poo.com',
],
]);
//取得 第2引数にtrueつけると連想配列
$obj = json_decode($res->getBody());
//取得
$status = $obj->status;
$message = $obj->message;
$email = $obj->email;
$rows = $obj->data;
//loop(参考)
foreach ($rows as $row) {
//echo $row->name;
}
//評価
$this->assertEquals("OK",$status);
$this->assertEquals("Hello POO.",$message);
$this->assertRegExp('/^Hello.+\.$/',$message);
$this->assertCount(2,$rows);
//データベースと連携
$user = \DB::table('users')->where('name','POO')->first();
$this->assertEquals("poo@poo.com",$user->email);
}
}
##テストの実行
###実行の前に
php-webdriverを正常に処理するためにはSelenium Server(Standalone)が起動している必要があります。
必要に応じてダウンロードし起動させておきます。
詳しくはこちらをご覧下さい。
###実行
Laravelにおけるテストの実行はtestsディレクトリにいるもとすると、
./vendor/bin/phpunit tests/
とすれば実行されます。
##その他
LaravelではTest用クラスが拡張されているため、独自のassertが使えます。
詳しくはこちら。