Laravel の HTTP Test
Laravel には HTTP テストという機能がある
このテストはめちゃめちゃ便利で、実際にリクエストを送って、返ってくるレスポンスをシミュレートできる。
<?php class ExampleTest extends TestCase { public function test_a_basic_request() { $response = $this->get('/'); $response->assertStatus(200); } }
HTTP Test の課題
Laravel で Json API サーバーを実装している場合、Json 関連のアサーションメソッドは充実しているため、特に困らない。
<?php class ExampleTest extends TestCase { public function test_making_an_api_request() { $response = $this->postJson('/api/user', ['name' => 'Sally']); $response ->assertStatus(201) ->assertJson([ 'created' => true, ]); } }
しかし、HTML のレスポンスのテストを書くのは結構苦労した。本当は CSS セレクタや XPath などで DOM を取得して、それに対してテストを書きたいのだが、残念ながらそのようなアサーションメソッドは無い。
ではどうやってテストするか。
HTML レスポンスのテスト方法
1. Laravel に用意されているアサーションで頑張る
1つ目は、Laravel に用意されているアサーションで頑張る。
レスポンスボディのアサーションに使えそうなメソッドは以下である
$response->assertSee($value, $escaped = true);
- レスポンスのHTMLに、$value という文字が登場しているかどうかをテストする。$value には HTML を指定することもできる。$value に HTML を指定したい場合は $escaped に false を選択する必要がある
- 例:
$response->assertSee('<h1>ページタイトル</h1>', false);
$response->assertSeeInOrder(array $values, $escaped = true);
- assertSee の $value の部分に複数の string を指定でき、文字列がその順番で登場していることが確認できる
- 例:
$response->assertSeeInOrder(['<body>', '文言1', '文言2', '</body>'], false);
- $response->assertSeeText($value, $escaped = true);
- assertSee とは異なり、HTML タグを除いた文字の部分だけ比較する。HTMLの構造などをテストするのではなく、単に、文言が表示されているかどうかをテストしたい場合はこちらを使うと良い
- $response->assertSeeTextInOrder(array $values, $escaped = true);
- seeText の複数文言版
この4つを使えば、十分 HTML のテストをすることはできる。欠点は、アサーションに失敗した時のエラー文言が見づらいことくらい。
2. HTML をパースするライブラリを別に導入する
基本的には上記 assertSee
を使えばだいたいのテストはできる。しかし、複雑なテストになると assertSee だけではテストできない。また、テストに失敗した時のエラー文言が非常に見づらい。
そこで、 HTML をパースするライブラリを使ってテストする方法もある。
凝ったテストを書きたい場合には非常に有効。
デメリットとして、
- ライブラリの依存関係が増え、ライブラリのメンテなどが大変になる
- テストの実装が複雑になる
といったことが挙げらる。
個人的には、テストの利便性向上のメリットに比べて、かかるコストがおもすぎるので、あまりオススメできません。assertSee などを駆使した方が良いかなという印象です。
3. 正規表現を駆使してテストを書く
HTMLのパースがコスト高いとなれば、正規表現を使う方法があります。
正規表現を使うメリットとしては、追加でライブラリをインストールする必要が無い点です。
デメリットは、正規表現を書くのが大変な点です。
しかし、実際にテストを書いてみると、意外と assertSee / assertSeeInOrder などで十分なテストが書けます。