Laravel+Codeceptionのメリット

私は普段、Laravel+Codeceptionを利用してテストを書いています。
今回はLaravel+Codeceptionのメリットとちょっとした小技を紹介します。

Codeceptionとは

CodeceptionPHPのテスティングフレームワークです。
単体テスト・機能テスト・受け入れテストを書けます。
多くのフレームワークをサポートしているのが特徴です。

LaravelでCodeceptionを使用するメリット

Laravelにはテスト機能がついています。
特にLaravel5.4からはLaravel Duskがあるので、Codeceptionの機能をすべてカバーしています。
なので、基本的にはわざわざCodeceptionを利用するメリットはありません。
それでもCodeceptionを利用するメリットとしては、以下のようなものがあります。

特定のフレームワークに縛られない

Laravelのテスト機能を使用してテストを書くと、Laravelから他のフレームワークに乗り換えづらくなります。
Codeceptionを利用する場合は、フレームワークを乗り換えてもテストのロジックはそのまま移行できます。

テスティングフレームワークを統一できる

チーム内で使用しているフレームワークが複数ある場合、それぞれのフレームワークのテスト機能を使用してテストを書くと学習コストが高く付きます。
フレームワークのテスト機能を使用せずにCodeceptionで統一すると学習コストを低く抑えられます。

CodeceptionでLaravel5Moduleを使用するメリット

Codeceptionはそれだけで十分にテストを書くことができますが、Laravel5Moduleを使用することでLaravelの機能を利用してテストを書くことができます。

環境ファイルを使用できる

.env.testing という環境ファイルを作成することで、テスト時にデータベースの接続設定などの環境変数を変更することができます。

DB機能を使用できる

テスト実行時に自動でマイグレーションを実行できたり、自動でDatabaseSeederをもとにデータを投入できます。
テスト前にトランザクションを張って、データを変更させないようにもできます。

EloquentModelを使用できる

データベーステストをする際に、 $I->seeRecord(Article::class, ['title' => 'test']) のようにEloquentのモデルを指定することができます。

ルーティングを使用できる

現在のURLをテストする際には

<?php
$I->seeCurrentPageIs("articles/{$article->id}/show")

のように書きますが、代わりに

<?php
$I->seeCurrentRouteIs('articles.show', $article)

のように書けます。 結構シンプルに書けるようになるのでオススメです。

小技:FactoryMuffinを使用しない

Fakerを利用してテストデータを生成したい場合、Codeceptionの公式ドキュメントでは、FactoryMuffinを使用するように書いてあります。
が、以下の理由からあまり使いやすくありません。

  • PHPDocTagの不足でIDEで補完できない
  • FactoryMuffinの定義の中でEloquentを使用できない

LaravelにはすでにFakerを使用してデータを作成する方法が存在するので、FactoryMuffinを使用せずに以下のようなヘルパーを書いて使っています。

<?php
    /**
     * {@inheritdoc}
     *
     * @return \Illuminate\Database\Eloquent\Model
     * @throws \InvalidArgumentException
     */
    public function have($name, $extraAttrs = [])
    {
        return factory($name)->create($extraAttrs);
    }

    /**
     * {@inheritdoc}
     *
     * @return \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model[]
     * @throws \InvalidArgumentException
     */
    public function haveMultiple($name, $times, $extraAttrs = [])
    {
        return factory($name, $times)->create($extraAttrs);
    }