web-dev-qa-db-ja.com

最初のテストを実行する前にPHPUnitをセットアップし、最後のテストを実行した後に破棄する

PHPUnitを使用してphpアプリケーションのDjangoテストユーティリティのように実装しようとしています。Djangoのように、メインから個別のテストデータベースが作成される最初のテストを実行する前にデータベースを保存し、最後のテストを実行した後にデータベースを削除します。一度に多くのテストケースを実行する場合でも、テストデータベースを作成する必要があるのは1回だけです。

このために、私は次のアプローチをとりました-

カスタムテストスイートクラスを定義して、セットアップとティアダウンメソッドでデータベースを作成およびドロップするコードを記述し、このクラスを使用して次のようにテストを実行できるようにしました

$ phpunit MyTestSuite

MyTestSuiteは、suiteという名前の静的メソッドを定義します。ここで、globを使用して、次のようにテストスイートにテストを追加します。

public static function suite() {
    $suite = new MyTestSuite();

    foreach (glob('./tests/*Test.php') as $tc) {
        require_once $tc;
        $suite->addTestSuite(basename($tc, '.php'));
    }

    return $suite;
}

すべてのテストケースクラスはPHPUnit_Framework_TestCaseのサブクラスから拡張され、このクラスのセットアップおよびティアダウンメソッドは、jsonフィクスチャファイルからの初期データのロードおよびクリアを処理します。

今はノーとして。テストが増えていますが、一度に実行する必要があるのは選択したテストのみです。しかし、私はすでにテストスイートを使用してテストを読み込んでいるため、-filterオプションは使用できません。これは、このアプローチが正しいものではなかったかもしれないと私に感じさせます。

だから私の質問は、PHPUnitがどのようにそれらを見つけるかに関係なく、最初のテストを実行する前と最後のテストを実行した後に何かを行うための正しいアプローチは何ですか?

PS:私は、PHPUnit_Extensions_Database_TestCaseを使用していませんが、dbの作成、データ投入、およびドロップの独自の実装を使用しています。

21
naiquevin

"Test Suites"を使用しない私の2つの自発的なアイデア。下の方にあります。

テストリスナー

PHPUnits test listeners を使用すると、

  public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
       if($suite->getName() == "yourDBTests") { // set up db
  }

  public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
       if($suite->getName() == "yourDBTests") { // tear down db
  }

in the docs のように、xml構成ファイルのテストスイートですべてのDBテストを定義できます。

<phpunit>
  <testsuites>
    <testsuite name="db">
      <dir>/tests/db/</dir>
    </testsuite>
    <testsuite name="unit">
      <dir>/tests/unit/</dir>
    </testsuite>
  </testsuites>
</phpunit>

Bootstrap

Phpunits bootstrapファイルを使用すると、DBを作成し、プロセスの終了時にそれ自体の__destructメソッドで破棄するクラスを作成できます。

オブジェクトへの参照をグローバルスコープに置くと、オブジェクトはすべてのテストの最後にのみ分解されます。 (@beanlandが指摘したように:register_shutdown_function()を使用することは、全体的にもっと理にかなっています!)


テストスイートの使用:

http://www.phpunit.de/manual/3.2/en/organizing-test-suites.html 表示:

<?php

class MySuite extends PHPUnit_Framework_TestSuite
{
    public static function suite()
    {
        return new MySuite('MyTest');
    }

    protected function setUp()
    {
        print "\nMySuite::setUp()";
    }

    protected function tearDown()
    {
        print "\nMySuite::tearDown()";
    }
}

class MyTest extends PHPUnit_Framework_TestCase
{
    public function testWorks() {
        $this->assertTrue(true);
    }
}

これはPHPUnit 3.6でうまく機能し、3.7でも機能します。 「テストスイートクラス」はやや非推奨/推奨されていないため、現在のドキュメントには含まれていませんが、かなり前から存在します。


各テストケースのデータベース全体を破棄して設定することは、テスト間の依存関係を解消するのに非常に役立ちますが、メモリ(sqliteメモリなど)でテストを実行しない場合、速度は価値がない場合があります。

17
edorian

最近、同じ問題を解決する必要がある場所に遭遇しました。カスタムクラスの__destructメソッドを使用して Edorianの回答 を試しましたが、allの最後ではなく、すべてのテストの最後に実行されたようですテスト。

Bootstrap.phpファイルで特別なクラスを使用する代わりに、PHPの register_shutdown_function 関数を使用して、すべてのテストの終了後にデータベースのクリーンアップを処理しましたが、完全に機能しているようでした。

これが私のbootstrap.phpファイルにあるものの例です

register_shutdown_function(function(){
   some_db_cleanup_methods();
});
35
Ian Hunter