こんにちは、ディレクターのエリカです。
エンジニアに仕様を伝えるのって大変ですよね。そもそも、仕様を詰めきれてなかったり、抜けてたりすることもありますし。
そこで、テストコードを渡すことができたら、素敵ですよね。Laravelならできちゃいます。
テスト環境の準備
今回もLaradockの利用が前提です。
PHPフレームワーク「Laradock」で、手軽にLaravel+Dockerな開発環境を構築する
冪等性を担保するためにテスト実行時は毎回データベースをリセットしたいですから、そのための設定を行います。といっても環境ファイルを変更するだけになります。こうしておけばまかり間違って本番環境でテストを実行してしまっても、データが削除されることはありません。
Laravelをセットアップしたディレクトリの /phpunit.xml
には以下のように記述されており、テスト実行時は、 APP_ENV
が testing
に切り替わります。そのため、 .env.testing
という環境ファイルを用意しておけば、自動でその内容が適用されます。
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="MAIL_DRIVER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
</php>
.env.testing
では、データベースの設定をテストを実行する環境に合わせて変更しておきます。
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=testing
DB_USERNAME=test_user
DB_PASSWORD=test_password
Laradockを利用している場合はこんな感じです。また、 test_user
が操作可能な testing
データベースを作成しておきます。
テストコードの準備
artisan
コマンドを使います。
Laradock
を利用している場合は、 workspace
コンテナに接続します。
artisan make:test ApiTest
を実行すると、 tests/Feature/ApiTest.php
が作成されます。
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ApiTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testExample()
{
$this->assertTrue(true);
}
}
テストを実行してみます。
phpunit ./tests/Feature/ApiTest
PHPUnit 7.4.5 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)
Time: 3.11 seconds, Memory: 18.00MB
OK (1 test, 1 assertion)
初期で設定されているテストのみですので、成功します。
テストコードの作成
それでは、テストを書いていきます。
テストのたびにデータベースのマイグレーションリセットが自動で実行されるように、トレイトを指定します。
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ApiTest extends TestCase
{
use RefreshDatabase; // 追加
/**
* A basic test example.
*
* @return void
*/
public function testExample()
{
$this->assertTrue(true);
}
}
こうしておくことにより、テストのたびに artisan migration:reset
相当の処理が行われます。
正常系のテスト
ファイルのアップロードを受けつけるAPIがあると想定し、そのAPIを利用したファイルのアップロードが成功するか、というテストコードを書いてみたいと思います。
public function testFileUpload()
{
// 1
\Storage::fake('files');
// 2
$file = UploadedFile::fake()->image('dummy.jpg', 800, 800);
// 3
$this->json('POST', '/api/v1/files', [
'file' => $file,
]);
// 4
\Storage::disk('files')->assertExists($file->name);
}
-
\Storage::fake('testing');
テスト用のモックストレージを用意します。- ダミーの画像ファイルを用意します。
- ファイルアップロードAPIにデータを送信します。
- ストレージのモックに送信したファイルが保存されているかをテストします。
これは、想定どおりの動作を確認するための正常系のテストになります。
次に異常系のテストコードを書いてみたいと思います。
異常系のテスト
次に、対象外のファイルが送信されたときにファイルが保存されないことをテストするコードです。
public function testFailFileUpload()
{
\Storage::fake('testing');
// 1
$file = UploadedFile::fake()->image('dummy.jpg', 80, 80);
$this->json('POST', '/api/v1/files', [
'file' => $file,
]);
// 2
\Storage::disk('testing')->assertMissing($file->name);
}
-
- ダミーの小さい画像を作成します。
- モックストレージに保存されていないことをテストしています。
これは、画像の縦横のサイズに制限がある場合に、その制限に引っかかったため、アップロードに失敗するということを意図したテストになります。
まとめ
正常系のテストコードは、APIを実装していない場合はもちろん失敗しますが、このようにさまざまなテストをコードベースで準備することができます。
仕様を決めてテストコードを先に記述しておけば、エンジニアが仕様に悩まずに実装できますし、メンテナンスされない無駄なドキュメントを作らずに済みます。テストを書く工数はかかりますが、Laravelはこのあたりも洗練されていますので、簡単に書くことができてすばらしいですね。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。