簡體   English   中英

按特定順序運行 PHPUnit 測試

[英]Run PHPUnit Tests in Certain Order

有沒有辦法讓TestCase的測試按特定順序運行? 例如,我想將對象的生命周期從創建到使用再到銷毀分開,但我需要確保在運行其他測試之前先設置對象。

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);
    }
}

但是,重要的是要注意具有未解析依賴項的測試將不會被執行(這是可取的,因為這會很快引起對失敗測試的關注)。 因此,在使用依賴項時密切注意是很重要的。

也許您的測試中存在設計問題。

通常每個測試不得依賴於任何其他測試,因此它們可以按任何順序運行。

每個測試都需要實例化和銷毀它運行所需的一切,這將是完美的方法,你不應該在測試之間共享對象和狀態。

您能否更具體地說明為什么 N 個測試需要相同的對象?

正確的答案是正確的測試配置文件。 我遇到了同樣的問題,並通過使用必要的測試文件順序創建測試套件來修復它:

phpunit.xml:

<phpunit
        colors="true"
        bootstrap="./tests/bootstrap.php"
        convertErrorsToExceptions="true"
        convertNoticesToExceptions="true"
        convertWarningsToExceptions="true"
        strict="true"
        stopOnError="false"
        stopOnFailure="false"
        stopOnIncomplete="false"
        stopOnSkipped="false"
        stopOnRisky="false"
>
    <testsuites>
        <testsuite name="Your tests">
            <file>file1</file> //this will be run before file2
            <file>file2</file> //this depends on file1
        </testsuite>
    </testsuites>
</phpunit>

如果您希望您的測試共享各種輔助對象和設置,您可以使用setUp()tearDown()添加到sharedFixture屬性。

PHPUnit 允許使用“@depends”注釋,它指定依賴測試用例並允許在依賴測試用例之間傳遞參數。

替代解決方案:在測試中使用 static(!) 函數來創建可重用元素。 例如(我使用 selenium 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();
    }
  • 通過這種方式,您可以構建測試的層次結構。
  • 您可以保留每個測試用例與其他測試用例完全分開的屬性(如果您在每次測試后清理數據庫)。
  • 最重要的是,例如,如果以后登錄方式發生變化,您只需修改 LoginTest 類,而其他測試中不需要正確的登錄部分(它們應該在更新 LoginTest 后工作):)

當我運行測試時,我的腳本開始清理 db ad。 上面我使用我的SeleniumClearTestCase類(我在那里制作了屏幕截圖()和其他不錯的函數)它是MigrationToSelenium2擴展(來自 github,使用 seleniumIDE + ff 插件“Selenium IDE: PHP Formatters”在 firefox 中移植記錄的測試),它是我的類 LaravelTestCase(它是 Illuminate\\Foundation\\Testing\\TestCase 的副本,但不是擴展 PHPUnit_Framework_TestCase),它設置 Laravel 以在我們想要在測試結束時清理數據庫時訪問 eloquent)它是 PHPUnit_Extensions_Selenium2TestCase 的擴展。 為了設置 laravel eloquent,我也在 SeleniumClearTestCase 函數 createApplication (在setUp調用,我從 laral test/TestCase 獲取這個函數)

在我看來,采用以下場景,我需要測試特定資源的創建和銷毀。

最初我有兩種方法,一個。 testCreateResource 和 b。 測試銷毀資源

一種。 測試創建資源

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

測試銷毀資源

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

我認為這是一個壞主意,因為 testDestroyResource 依賴於 testCreateResource。 更好的做法是做

一種。 測試創建資源

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

測試銷毀資源

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

如果您的測試需要按特定順序運行,則確實存在問題。 每個測試都應該完全獨立於其他測試:它可以幫助您定位缺陷,並允許您獲得可重復(因此可調試)的結果。

查看此站點以獲取大量想法/信息,了解如何以避免此類問題的方式分解測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM