経緯
「とりあえずHTTPテストやりたいけど、構造はよく変わるしテストの維持がとても大変」
「関係ないけどsitemap.xmlの更新も面倒だなぁ」
「そうだ!sitemap.xmlからテストを作れば1度の修正で済むぞ!」
環境
laravel 6.19
PHPUnit 8.2.5
備考
前提として、テストを行うルート(sitemap.xmlに載せているルート)にnameが設定されている必要があります。
このテストは「sitemap.xml(このサイトに存在すると世界に示しているページ)にアクセス可能か」ということだけを検証するものです。
テストの管理が難しい環境で、最低限のHTTPテストとしてとりあえず入れてみるのには良いのでは無いかと思います。
出来たもの
sitemap/index.blade.php
<?php echo '<?xml version="1.0" encoding="UTF-8" ?>' . "\n"; ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>{{ route('home') }}</loc>
<changefreq>daily</changefreq>
</url>
<url>
<loc>{{ route('info') }}</loc>
<changefreq>daily</changefreq>
</url>
{{--こういうshowページあったとする--}}
@foreach($articles as $article)
<url>
<loc>{{ route('article.show', ['id' => $article->id]) }}</loc>
<changefreq>daily</changefreq>
</url>
@endforeach
</urlset>
SiteMapTest.php
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class SiteMapTest extends TestCase
{
/**
* 同一ルートを何個試すか
*/
private $count = 3;
/**
* @test
* @group sitemap
* @dataProvider additionPrivateItems
* @param string $url
*/
public function test(string $url)
{
$response = $this->get($url);
$response->assertStatus(200);
}
public function additionPrivateItems()
{
$xmlData = simplexml_load_string(view('sitemap.index')->render());
$data = json_decode(json_encode($xmlData), TRUE)['url'];
shuffle($data);
foreach ($data as $url) {
$url = $url['loc'];
$routeName = $this->getRouteName(parse_url($url, PHP_URL_PATH) ?? '');
if (empty($routes[$routeName]))
$routes[$routeName] = 1;
elseif ($routes[$routeName] >= $this->count)
continue;
else
$routes[$routeName]++;
yield [$url];
}
}
private function getRouteName(string $uri)
{
return app('router')->getRoutes()->match(app('request')->create($uri))->getName();
}
}
コードの中身
PHPunitのdataProviderを使ってテストケースを作っています。
laravelなら大体sitemap.xmlはblade使って生成していると思うので、
- viewを
->render()
で文字列として取得 - xml文字列を
simplexml_load_string
で取得 - あれやこれやして配列で取得
- 毎回ランダムなルートをテスト出来るようにシャッフルする
- foreachで回し、それぞれURIからルート名を取得
- 同じルートだったら個数制限する
という流れです。
PHPunitのgroupを設定しているので
./vendor/bin/phpunit --group=sitemap
これで実行出来ます。
終わり
これは本当に最低限の機能テストなので、フォームの送信テストなどPOST系のテストは別に用意出来ると良いです。
全部ルーティングから自動生成出来たらな。