View on GitHub

Codeception.docs.ja

Codeception docs japanese translation

Download this project as a .zip file Download this project as a tar.gz file

単体テスト

Codeceptionはテストの実行環境としてPHPUnitを使用しています。したがって、PHPUnitのどのテストでもCodeceptionのテストスイートに追加できますし、実行できます。 いままでにPHPUnitテストを書いていたならば、これまで書いてきたようにするだけです。 Codeceptionは簡単な共通処理に対して、すばらしいヘルパー機能を追加しています。

単体テストの基礎はここでは割愛する代わりに、単体テストにCodeceptionが追加する特徴の基礎知識をお伝えしましょう。

もう一度言います: テストを実行するためにPHPUnitをインストールする必要はありません。Codeceptionも実行できます。

テストを作成する

Codeceptionは簡単にテストを作成する、すばらしいジェネレーターを持っています。 \PHPUnit_Framework_TestCaseクラスを継承している従来のPHPUnitテストを生成するところから始める事ができます。 以下のようなコマンドで生成されます。

$ php codecept.phar generate:phpunit unit Example

Codeceptionは一般的な単体テストのアドオンを備えています、それでは試してみましょう。 Codeceptionの単体テストを作成するには別のコマンドが必要です。

$ php codecept.phar generate:test unit Example

どちらのテストもtests/unitディレクトリに新しくExampleTestファイルを作成します。

generate:testによって作成されたテストは、このようになります。

<?php
use Codeception\Util\Stub;

class ExampleTest extends \Codeception\TestCase\Test
{
   /**
    * @var UnitTester
    */
    protected $tester;

    // 各テスト前に実行される
    protected function _before()
    {
    }

    // 各テスト後に実行される
    protected function _after()
    {
    }
}
?>

このクラスは、はじめから_before_afterのメソッドが定義されています。それらは各テスト前にテスト用のオブジェクトを作成し、終了後に削除するのに使用できます。

ご覧の通り、PHPUnitとは違い、setUptearDownメソッドがエイリアス: _before, _afterされています。

実際にはsetUptearDownメソッドは、親クラスの\Codeception\TestCase\Testクラスに実装されており、さらに単体テストの一部として実行できるように、Ceptファイルからすべてのすてきなアクションを持ったUnitTesterクラスがセットアップされています。受け入れテストや機能テストのように、unit.suite.ymlの設定ファイルの中でUnitTesterクラスが使う適切なモジュールを選べます。

# Codeception Test Suite Configuration

# suite for unit (internal) tests.
class_name: UnitTester
modules:
    enabled: [UnitHelper, Asserts]

従来の単体テスト

Codeceptionの単体テストは、PHPUnitで書かれているのとまったく同じように書かれています。:

<?php
class UserTest extends \Codeception\TestCase\Test
{
    public function testValidation()
    {
        $user = User::create();

        $user->username = null;
        $this->assertFalse($user->validate(['username']));

        $user->username = 'toolooooongnaaaaaaameeee';
        $this->assertFalse($user->validate(['username']));

        $user->username = 'davert';
        $this->assertTrue($user->validate(['username']));           
    }
}
?>

BDD Spec テスト

テストを書くときは、アプリケーションにおける一定の変化のためにテストを準備する必要があります。テストは読みやすく維持されやすくするべきです。あなたのアプリケーションの仕様が変わったら、同じようにテストもアップデートされるべきです。ドキュメントのテストにおいてチーム内部で話し合いが持たれなかったのならば、新しい機能の導入によってテストが影響を受けるということを理解していくのに壁があるでしょう。

そのため、アプリケーションを単体テストで網羅するだけでなく、テスト自体を説明的に保っておくことはとても重要な事です。私たちは、シナリオ駆動の受け入れテストと機能テストでこれを実践しています。そして、単体テストや結合テストにおいても同様にこれを実践するべきです。

この場合において、単体テスト内部の仕様を書いているSpecify (pharパッケージしている)というスタンドアロンのプロジェクトを用意しています。

<?php
class UserTest extends \Codeception\TestCase\Test
{
    use \Codeception\Specify;

    public function testValidation()
    {
        $user = User::create();

        $this->specify("username is required", function() {
            $user->username = null;
            $this->assertFalse($user->validate(['username']));
        });

        $this->specify("username is too long", function() {
            $user->username = 'toolooooongnaaaaaaameeee';
            $this->assertFalse($user->validate(['username']));
        });

        $this->specify("username is ok", function() {
            $user->username = 'davert';
            $this->assertTrue($user->validate(['username']));           
        });     
    }
}
?>        

specifyのコードブロックを使用する事で、テストを細かい単位で説明することができます。このことはチームの全員にとってテストがとても見やすく、理解しやすい状態にしてくれます。

specifyブロックの内部にあるコードは独立しています。上記の例だと、$this->user(他のどんなオブジェクトやプロパティでも)への変更は他のコードブロックに反映されないでしょう。

あなたはBDD-styleのアサーションをするために、Codeception\Verifyも追加するかもしれません。もし、あなたがassertの呼び出しの中で、引数のどちらが期待している値で、どちらが実際の値なのかをよく混同してしまうなら、この小さなライブラリはとてもすばらしく可読性に長けたアサーションを追加します。

<?php
verify($user->getName())->equals('john');
?>

モジュールを使う

シナリオ駆動の機能テストや受け入れテストの中で、あなたはアクタークラスのメソッドにアクセスできました。もし結合テストを書く場合は、データベースをテストするDbモジュールが役に立つかもしれません。

# Codeception Test Suite Configuration

# suite for unit (internal) tests.
class_name: UnitTester
modules:
    enabled: [Db, UnitHelper]

UnitTesterのメソッドにアクセスする事で、テストの中でUnitTesterのプロパティを使用できます。

データベーステスト

それでは、どのようにデータベースのテストができるのか、見て行きましょう:

<?php
function testSavingUser()
{
    $user = new User();
    $user->setName('Miles');
    $user->setSurname('Davis');
    $user->save();
    $this->assertEquals('Miles Davis', $user->getFullName());
    $this->tester->seeInDatabase('users', array('name' => 'Miles', 'surname' => 'Davis'));
}
?>

単体テストでデータベース機能を有効にするためには、unit.suite.yml設定ファイルにて有効なモジュール一覧に Db モジュールが含まれていることを確認してください。 受け入れテストや機能テストのように、データベースはテストが終了するごとに、クリーンにされて構築されるでしょう。 それが必要のない振る舞いであれば、現在のスイートのDbモジュールの設定を変更してください。

モジュールにアクセスする

Codeceptionはこのスイートにおいて、すべてのモジュールに定義されたプロパティとメソッドにアクセスする事を許可しています。このときはUnitTesterクラスを使うときとは違い、直接モジュールを使用する事で、モジュールのすべてのパブリックなプロパティへのアクセスを得られます。

たとえば、もしSymfony2を使うなら、このようにSymfonyのコンテナにアクセスします:

<?php
/**
 * @var Symfony\Component\DependencyInjection\Container
 */
$container = $this->getModule('Symfony2')->container;
?>

すべてのパブリックな変数は、そのモジュールに対応するリファレンスにリストされています。

Cest

PHPUnit_Framework_TestCaseを継承したテストケースの代わりに、Codeception仕様のCest形式を使用できるでしょう。他のどのクラスも継承する必要はありません。このクラスのすべてのパブリックなメソッドがテストです。

上記の例をシナリオ駆動の形式でこのように書きなおすことができます:

<?php
class UserCest
{
    public function validateUser(UnitTester $t)
    {
        $user = $t->createUser();
        $user->username = null;
        $t->assertFalse($user->validate(['username']); 

        $user->username = 'toolooooongnaaaaaaameeee';
        $t->assertFalse($user->validate(['username']));

        $user->username = 'davert';
        $t->assertTrue($user->validate(['username']));

        $t->seeInDatabase('users', ['name' => 'Miles', 'surname' => 'Davis']);
    }
}
?>

$t変数でアクセスしているであろう、UnitTesterクラスのいつものアサーションを追加するAssertsモジュールを単体テストのために追加するかもしれません。

# Codeception Test Suite Configuration

# suite for unit (internal) tests.
class_name: UnitTester
modules:
    enabled: [Asserts, Db, UnitHelper]

Cest形式について もっと知る.

スタブ

Codeceptionは、スタブを簡単に作成するPHPUnitモックフレームワークの小さいラッパーを提供しています。\Codeception\Util\Stubを追加して、ダミーオブジェクトの作成を始めてください。

この例では、コンストラクタを呼び出さずにオブジェクトを初期化し、getNameメソッドがjohnという値を返すように置き換えています。

<?php
$user = Stub::make('User', ['getName' => 'john']);
$name = $user->getName(); // 'john'
?>

スタブはPHPUnitのモックフレームワークから生成されます。MockeryMockery moduleとセット)、AspectMock、など他のものを代わりに使用することもできます。

スタブのユーティリティクラスの全リファレンスはここを見てください。

まとめ

テストスイートの中で、PHPUnitのテストはfirst-class citizensです。単体テストを書いて実行したいときはいつでも、PHPUnitをインストールする必要はなく、そのままCodeception上で実行することができます。いくつかのすばらしい特徴は、Codeceptionモジュールを統合する事で共通の単体テストを追加できることです。単体テストや結合テストのほとんどにおいて、PHPUnitのテストだけで十分です。PHPUnitのテストは速く、維持しやすいからです。