★テスト駆動

[記事]

qiita.com


CircleCIのconfig.ymlの書き方

circleci.com


生成コマンド

$ php artisan make:test --unit Models/UserProfileTest


実行コマンド

$ ./vendor/bin/phpunit --testdox --testsuite=Unit
$ ./vendor/bin/phpunit --testdox --testsuite=Feature


Tests\TestCase クラスを継承することで
Laravel の内部の機能にアクセスできるようになる。



Tests\TestCase を継承しているのは
Feature のほうだけで、
Unit にあるほうは
PHPUnit が提供している基底クラスを継承している。


これは、ユニットテストフレームワークの機能に依存しない形で書くことが望ましい、 という考え方に基づいている。


これはあくまで原則であって、 フレームワークの機能(たとえば Facade など)を
利用したユニットテストを書きたい場合は、
継承元のクラスを Tests\TestCase に変更すること。


tests/Unit/ExampleTest.php

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;

class ExampleTest extends TestCase



tests/Feature/ExampleTest.php

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ExampleTest extends TestCase



Laravel によって追加されたアサーションメソッド



HTTPレスポンスのテスト (feature test)



[*] get()メソッド

Tests\TestCaseにはget()メソッドが含まれる。
働きは、アプリケーションに対して、GETリクエストを作成。
戻り値は、HTTPレスポンス。

readouble.com

getメソッドは
アプリケーションに対して、GETリクエストを作成します。



(1) assertStatus

$response = $this->get('/');
$response->assertStatus(200); 

assertStatusメソッドは
返されたレスポンスが
指定したHTTPステータスコードを持っていることをアサートします。
このシンプルな例に加え、
レスポンスヘッダ、コンテンツ、JSON構造などを
検査するさまざまなアサートをLaravelは用意しています。

featureテストの概要 [Controller単位]

フィーチャーテストでは、
複数のクラスが連動するような処理の実行後の状態を確認する。
ウェブサービスでは、一般的に、
Controller を対象とし、
HTTP リクエストを入力値、
レスポンスを出力値として検査する。

Unitテストの概要 [Function単位]

ユニットテストでは、
単一あるいは少数の小さなクラスの集まりが提供する機能(関数)の動作を確認する。

原則的には、 フレームワークやアプリケーション以外の要素(データベースや外部 APIなど)に
依存しないようにテスト対象を組み立てるが、
そうした要素を切り離すことでかえって設計が複雑になるようであれば、
それらを含めた上でユニットテストを書くこともある。



データプロバイダ @dataProvider

PHPUnit ではデータプロバイダという仕組みを使って、
テストパターンを配列で定義し、
テストメソッドに順に渡してテストを行うことができる。
以下のように @dataProvider メソッド名 の形式で、
テストメソッドの DocComment 内に書く。


リフレクションクラスの使用法, invokeの第2引数

/**
     * @test
     * 
     * invoke()メソッドの第1引数には、
     * メソッドが属するクラスのインスタンスを指定します。
     * 第2引数以降には引数を指定します。
     * https://blog.asial.co.jp/751
     * 
     */

    public function changeUSDIntoJPY()
    {
        $reflection = new \ReflectionClass($this->object);
        $method = $reflection->getMethod('changeUSDIntoJPY');
        $method->setAccessible(true);


        $res = $method->invoke($this->object, '3,100');
        $expectedValue = 3100 * 121;

        $this->assertSame($expectedValue, $res);
    }



RefreshDatabase

TestCaseクラスを継承したクラスでRefreshDatabaseトレイトを使用すると、
データベースをリセットします。

なお、トレイトは継承と似たPHPの機能で、
汎用性の高いメソッドなどをトレイトとしてまとめておき、
他の複数のクラスで共通して使う、といった使い方をします。

リセットするとはどういうことかというと、
データベースの全テーブルを削除(DROP)した上で、
マイグレーションを実施し全テーブルを作成します。

なお、RefreshDatabaseトレイトを使用すると、
上記に加えて、テスト中にデータベースに
実行したトランザクション(レコードの新規作成・更新・削除など)は、
テスト終了後に無かったことになります。



リレーションのテスト

  • BelongsTo
  • hasMany
  • hasOne

medium.com

/**
     * @test
     */
    public function BelongsToUser()
    {
        /**
         * Relationのテストの仕方
         * [参照]
         * https://medium.com/@tonyfrenzy/part-2-testing-model-relationships-in-laravel-basic-8b606dd36c02
         */
        $user = factory(User::class)->create();
        $phone = factory(Tweet::class)->create(['user_id' => $user->id]); 

        $this->assertInstanceOf(User::class, $phone->user);
    }

テスト用のメソッド確認

phpunit.readthedocs.io