74

内のテストをTestCase特定の順序で実行する方法はありますか? たとえば、オブジェクトの作成から使用、破棄までのライフサイクルを分離したいのですが、他のテストを実行する前に、オブジェクトが最初に設定されていることを確認する必要があります。

4

8 に答える 8

152

PHPUnit は@dependsアノテーションを介してテスト依存関係をサポートします。

これは、依存関係を満たす順序でテストが実行され、各依存テストが引数を次のテストに渡すドキュメントの例です。

class StackTest extends PHPUnit_Framework_TestCase
{
    public function testEmpty()
    {
        $stack = array();
        $this->assertEmpty($stack);

        return $stack;
    }

    /**
     * @depends testEmpty
     */
    public function testPush(array $stack)
    {
        array_push($stack, 'foo');
        $this->assertEquals('foo', $stack[count($stack)-1]);
        $this->assertNotEmpty($stack);

        return $stack;
    }

    /**
     * @depends testPush
     */
    public function testPop(array $stack)
    {
        $this->assertEquals('foo', array_pop($stack));
        $this->assertEmpty($stack);
    }
}

ただし、依存関係が解決されていないテストは実行されないことに注意することが重要です (失敗したテストにすぐに注意が向けられるため、望ましいことです)。したがって、依存関係を使用するときは細心の注意を払うことが重要です。

于 2009-12-16T14:46:13.273 に答える
59

テストに設計上の問題がある可能性があります。

通常、各テストは他のテストに依存してはならないため、任意の順序で実行できます。

各テストは、実行する必要があるすべてのものをインスタンス化して破棄する必要があります。これは完璧なアプローチです。テスト間でオブジェクトと状態を共有しないでください。

N 個のテストに同じオブジェクトが必要な理由について、より具体的に説明できますか?

于 2008-08-13T20:13:42.830 に答える
8

テストでさまざまなヘルパーオブジェクトと設定を共有する場合はsetUp()、を使用tearDown()してプロパティに追加できsharedFixtureます。

于 2008-08-23T22:30:48.447 に答える
7

PHPUnit では、依存するテスト ケースを指定し、依存するテスト ケース間で引数を渡すことができる '@depends' アノテーションを使用できます。

于 2009-12-29T10:22:31.247 に答える
4

別の解決策: テストで static(!) 関数を使用して、再利用可能な要素を作成します。たとえば (私はセレン IDE を使用してテストを記録し、phpunit-selenium (github) を使用してブラウザー内でテストを実行します)

class LoginTest extends SeleniumClearTestCase
{
    public function testAdminLogin()
    {
        self::adminLogin($this);
    }

    public function testLogout()
    {
        self::adminLogin($this);
        self::logout($this);
    }

    public static function adminLogin($t)
    {
        self::login($t, 'john.smith@gmail.com', 'pAs$w0rd');
        $t->assertEquals('John Smith', $t->getText('css=span.hidden-xs'));
    }

    // @source LoginTest.se
    public static function login($t, $login, $pass)
    {
        $t->open('/');
        $t->click("xpath=(//a[contains(text(),'Log In')])[2]");
        $t->waitForPageToLoad('30000');
        $t->type('name=email', $login);
        $t->type('name=password', $pass);
        $t->click("//button[@type='submit']");
        $t->waitForPageToLoad('30000');
    }

    // @source LogoutTest.se
    public static function logout($t)
    {
        $t->click('css=span.hidden-xs');
        $t->click('link=Logout');
        $t->waitForPageToLoad('30000');
        $t->assertEquals('PANEL', $t->getText("xpath=(//a[contains(text(),'Panel')])[2]"));
    }
}

わかりました、そして今、私は他のテストでこの再利用可能な要素を使うことができます:)例:

class ChangeBlogTitleTest extends SeleniumClearTestCase
{
    public function testAddBlogTitle()
    {
      self::addBlogTitle($this,'I like my boobies');
      self::cleanAddBlogTitle();
    }

    public static function addBlogTitle($t,$title) {
      LoginTest::adminLogin($t);

      $t->click('link=ChangeTitle');
      ...
      $t->type('name=blog-title', $title);
      LoginTest::logout($t);
      LoginTest::login($t, 'paris@gmail.com','hilton');
      $t->screenshot(); // take some photos :)
      $t->assertEquals($title, $t->getText('...'));
    }

    public static function cleanAddBlogTitle() {
        $lastTitle = BlogTitlesHistory::orderBy('id')->first();
        $lastTitle->delete();
    }
  • このようにして、テストの階層を構築できます。
  • 各テスト ケースが他のテスト ケースと完全に分離されているというプロパティを維持することができます (各テストの後に DB をクリーンアップする場合)。
  • そして最も重要なのは、たとえば、将来ログインの方法が変更された場合、LoginTest クラスを変更するだけで、他のテストで正しいログイン部分を必要としない場合です (LoginTest の更新後に動作するはずです) :)

テストを実行すると、スクリプトが最初にデータベースをクリーンアップします。上記で私は自分のSeleniumClearTestCaseクラスを使用しています(私はそこにスクリーンショット()と他の素晴らしい関数を作ります)それはMigrationToSelenium2(githubから、seleniumIDE + ffプラグイン「Selenium IDE:PHPフォーマッター」を使用してfirefoxで記録されたテストを移植する)の拡張です。これは私のクラスの拡張ですPHPUnit_Extensions_Selenium2TestCase の拡張である LaravelTestCase (これは Illuminate\Foundation\Testing\TestCase のコピーですが、PHPUnit_Framework_TestCase を拡張したものではありません)。laravel eloquent をセットアップするために、SeleniumClearTestCase 関数 createApplication にもあります (これは at で呼び出されsetUp、laral test/TestCase からこの関数を取得します)

于 2016-06-17T10:31:05.743 に答える
2

私の見解では、特定のリソースの作成と破棄をテストする必要がある次のシナリオを取り上げます。

最初は2つの方法がありました。testCreateResource および b. testDestroyResource

a. testCreateResource

<?php
$app->createResource('resource');
$this->assertTrue($app->hasResource('resource'));
?>

b. testDestroyResource

<?php
$app->destroyResource('resource');
$this->assertFalse($app->hasResource('resource'));
?>

testDestroyResource は testCreateResource に依存するため、これは悪い考えだと思います。そして、より良い練習はすることです

a. testCreateResource

<?php
$app->createResource('resource');
$this->assertTrue($app->hasResource('resource'));
$app->deleteResource('resource');
?>

b. testDestroyResource

<?php
$app->createResource('resource');
$app->destroyResource('resource');
$this->assertFalse($app->hasResource('resource'));
?>
于 2010-03-28T10:42:21.223 に答える
1

特定の順序で実行する必要がある場合、テストには実際に問題があります。各テストは、他のテストから完全に独立している必要があります。これにより、欠陥の特定が容易になり、再現可能な (したがってデバッグ可能な) 結果を得ることができます。

このサイトをチェックして、この種の問題を回避する方法でテストを因数分解する方法について、アイデア/情報を大量に入手してください。

于 2008-08-14T15:39:32.847 に答える