PHPカンファレンス2022で フラットなPHPからオブジェクト指向で自動テストのあるPHPへ、そしてフレームワークへ を発表した際に、「クラス化されていないレガシーシステムに対してテストを書いてリファクタしていくにはどうすればいいか?」という質問を受けました。
その場で「自分で自分のシステムに対してスクレイピングすると良い」という形で言葉で回答はしましたが、実際にどうやるのか他に例が見当たらなかったので、この場を借りて走り書きですが例を示したいと思います。
テストしたい対象のレガシーシステム
このようなハイパーレガシーコードなシステムがあり、index.phpというURLでアクセスできるとします。
<?php
// index.php
$name = $_GET['name'];
?>
こんにちは<?php echo htmlspecialchars($name); ?>さん
スクレイピングによるテストをするための準備
テストはサーバー上で行わずローカルで行いましょう。
ローカルでコマンドラインでphpを使えるようにしたうえで、index.phpがあるディレクトリで下記のようなコマンドを実行し、開発用ウェブサーバーを起動しておきます。
php -S 127.0.0.1:8080 -t ./
スクレイピングするテストの書き方
phpunitの基本的な使い方等は別途ググってください。
スクレイピングテストの書き方のみ示します。
<?php
class IndexTest extends \PHPUnit\Framework\TestCase
{
public function test()
{
$client = \GuzzleHttp\Client();
$response = $client->request('GET', 'https://127.0.0.1:8080/index.php?name=77web');
$this->assertEquals(200, $response->getStatusCode());
$this->assertTrue(str_contains($response->getContent(), '77webさん'));
}
public function test_xss()
{
$client = \GuzzleHttp\Client();
$response = $client->request('GET', 'https://127.0.0.1:8080/index.php?name=<script>alert()</script>');
$this->assertEquals(200, $response->getStatusCode());
$this->assertTrue(str_contains($response->getContent(), '<script>'), 'エスケープされていること');
}
}
Guzzleを使って実際に開発ウェブサーバーのindex.phpにアクセスし、帰ってきたレスポンス内容をstr_contains関数で検査しています。
この例ではGuzzleを使っていますが、HTTP Clientのライブラリは他にも存在するので、使いやすいものを使えばOKです。
https://docs.guzzlephp.org/en/stable/
よりスクレイピングテストしやすいツール
Symfony BrowserKitコンポーネント は上の例のようなトラディショナルなHTMLを返すURLに対するスクレイピングテストを書くときに便利なツールとなっています。