0 追蹤者

夾具

夾具是測試的重要組成部分。它們的主要目的是在一個固定/已知的狀態下設定環境,以便您的測試是可重複的,並以預期的方式執行。Yii 提供了一個夾具框架,讓您可以精確地定義夾具,並在 Codeception 中執行測試以及獨立執行測試時輕鬆地使用它們。

Yii 夾具框架中的一個關鍵概念是所謂的夾具物件。夾具物件代表測試環境的特定方面,並且是 yii\test\Fixture 或其子類別的實例。例如,您可以使用 UserFixture 來確保使用者資料庫表包含一組固定的資料。您可以在執行測試之前載入一個或多個夾具物件,並在完成時卸載它們。

夾具可以依賴其他夾具,透過其 yii\test\Fixture::$depends 屬性指定。當夾具正在載入時,它所依賴的夾具將在該夾具之前自動載入;並且當夾具正在卸載時,依賴的夾具將在該夾具之後卸載。

定義夾具

要定義夾具,請建立一個新的類別,擴充 yii\test\Fixtureyii\test\ActiveFixture。前者最適合用於通用夾具,而後者具有專門為與資料庫和 ActiveRecord 協同運作而設計的增強功能。

以下程式碼定義了關於 User ActiveRecord 和相應使用者表的夾具。

<?php
namespace app\tests\fixtures;

use yii\test\ActiveFixture;

class UserFixture extends ActiveFixture
{
    public $modelClass = 'app\models\User';
}

提示:每個 ActiveFixture 都是關於為測試目的準備資料庫表。您可以透過設定 yii\test\ActiveFixture::$tableName 屬性或 yii\test\ActiveFixture::$modelClass 屬性來指定表。如果是後者,表名稱將從 modelClass 指定的 ActiveRecord 類別中取得。

注意:yii\test\ActiveFixture 僅適用於 SQL 資料庫。對於 NoSQL 資料庫,Yii 提供了以下 ActiveFixture 類別

  • Mongo DB:yii\mongodb\ActiveFixture
  • Elasticsearch:yii\elasticsearch\ActiveFixture(自 2.0.2 版本起)

ActiveFixture 夾具的夾具資料通常在位於 fixturepath/data/tablename.php 的檔案中提供,其中 fixturepath 代表包含夾具類別檔案的目錄,而 tablename 是與夾具關聯的表的名稱。在上面的範例中,該檔案應為 @app/tests/fixtures/data/user.php。資料檔案應傳回要插入使用者表中的資料列陣列。例如,

<?php
return [
    'user1' => [
        'username' => 'lmayert',
        'email' => 'strosin.vernice@jerde.com',
        'auth_key' => 'K3nF70it7tzNsHddEiq0BZ0i-OU8S3xV',
        'password' => '$2y$13$WSyE5hHsG1rWN2jV8LRHzubilrCLI5Ev/iK0r3jRuwQEs2ldRu.a2',
    ],
    'user2' => [
        'username' => 'napoleon69',
        'email' => 'aileen.barton@heaneyschumm.com',
        'auth_key' => 'dZlXsVnIDgIzFgX4EduAqkEPuphhOh9q',
        'password' => '$2y$13$kkgpvJ8lnjKo8RuoR30ay.RjDf15bMcHIF7Vz1zz/6viYG5xJExU6',
    ],
];

您可以為列賦予別名,以便稍後在您的測試中,您可以透過別名引用該列。在上面的範例中,兩列分別被別名為 user1user2

此外,您不需要為自動遞增的列指定資料。當夾具正在載入時,Yii 將自動將實際值填入列中。

提示:您可以透過設定 yii\test\ActiveFixture::$dataFile 屬性來自訂資料檔案的位置。您也可以覆寫 yii\test\ActiveFixture::getData() 以提供資料。

正如我們之前描述的,夾具可以依賴其他夾具。例如,UserProfileFixture 可能需要依賴 UserFixture,因為使用者個人資料表包含指向使用者表的外鍵。依賴關係透過 yii\test\Fixture::$depends 屬性指定,如下所示,

namespace app\tests\fixtures;

use yii\test\ActiveFixture;

class UserProfileFixture extends ActiveFixture
{
    public $modelClass = 'app\models\UserProfile';
    public $depends = ['app\tests\fixtures\UserFixture'];
}

依賴關係也確保了夾具以明確定義的順序載入和卸載。在上面的範例中,UserFixture 將始終在 UserProfileFixture 之前載入,以確保所有外鍵參考都存在,並且在 UserProfileFixture 卸載後卸載,原因相同。

在上面,我們展示了如何定義關於資料庫表的夾具。要定義與資料庫無關的夾具(例如,關於特定檔案和目錄的夾具),您可以從更通用的基底類別 yii\test\Fixture 擴充,並覆寫 load()unload() 方法。

使用夾具

如果您正在使用 Codeception 來測試您的程式碼,您可以使用內建的支援來載入和存取夾具。

如果您正在使用其他測試框架,您可以在您的測試案例中使用 yii\test\FixtureTrait 來達到相同的目標。

在下面,我們將描述如何使用 Codeception 編寫 UserProfile 單元測試類別。

在您的擴充 \Codeception\Test\Unit 的單元測試類別中,宣告您想要在 _fixtures() 方法中使用的夾具,或直接使用 actor 的 haveFixtures() 方法。例如,

namespace app\tests\unit\models;


use app\tests\fixtures\UserProfileFixture;

class UserProfileTest extends \Codeception\Test\Unit
{   
    public function _fixtures()
    {
        return [
            'profiles' => [
                'class' => UserProfileFixture::class,
                // fixture data located in tests/_data/user.php
                'dataFile' => codecept_data_dir() . 'user.php'
            ],
        ];
    }

    // ...test methods...
}

_fixtures() 方法中列出的夾具將在執行測試之前自動載入。正如我們之前描述的,當夾具正在載入時,它的所有依賴夾具將首先自動載入。在上面的範例中,由於 UserProfileFixture 依賴於 UserFixture,因此當在測試類別中執行任何測試方法時,將依序載入兩個夾具:UserFixtureUserProfileFixture

當為 _fixtures()haveFixtures() 指定夾具時,您可以使用類別名稱或組態陣列來引用夾具。組態陣列將讓您在載入夾具時自訂夾具屬性。

您也可以為夾具指派別名。在上面的範例中,UserProfileFixture 被別名為 profiles。在測試方法中,您可以接著在 grabFixture() 方法中使用其別名來存取夾具物件。例如,

$profile = $I->grabFixture('profiles');

將傳回 UserProfileFixture 物件。

由於 UserProfileFixtureActiveFixture 擴充,您可以進一步使用以下語法來存取夾具提供的資料

// returns the UserProfile model corresponding to the data row aliased as 'user1'
$profile = $I->grabFixture('profiles', 'user1');
// traverse data in the fixture
foreach ($I->grabFixture('profiles') as $profile) ...

組織夾具類別與資料檔案

預設情況下,夾具類別會在 data 資料夾下尋找相應的資料檔案,該資料夾是包含夾具類別檔案的資料夾的子資料夾。當您處理簡單的專案時,可以遵循此慣例。對於大型專案,您可能經常需要為不同測試的相同夾具類別切換不同的資料檔案。因此,我們建議您以類似於您的類別命名空間的階層方式組織資料檔案。例如,

# under folder tests\unit\fixtures

data\
    components\
        fixture_data_file1.php
        fixture_data_file2.php
        ...
        fixture_data_fileN.php
    models\
        fixture_data_file1.php
        fixture_data_file2.php
        ...
        fixture_data_fileN.php
# and so on

透過這種方式,您將避免測試之間夾具資料檔案的衝突,並根據需要使用它們。

注意:在上面的範例中,夾具檔案的命名僅用於範例目的。在現實生活中,您應該根據您的夾具類別擴充自哪個夾具類別來命名它們。例如,如果您從 yii\test\ActiveFixture 擴充用於資料庫夾具,則應使用資料庫表名稱作為夾具資料檔案名稱;如果您從 yii\mongodb\ActiveFixture 擴充用於 MongoDB 夾具,則應使用集合名稱作為檔案名稱。

可以使用類似的階層來組織夾具類別檔案。您可以想要使用 fixtures 作為根目錄,而不是使用 data 作為根目錄,以避免與資料檔案衝突。

使用 yii fixture 管理夾具

Yii 透過 yii fixture 命令列工具支援夾具。此工具支援

  • 將夾具載入到不同的儲存裝置,例如:RDBMS、NoSQL 等;
  • 以不同的方式卸載夾具(通常是清除儲存裝置);
  • 自動產生夾具並使用隨機資料填充它。

夾具資料格式

假設我們有夾具資料要載入

#users.php file under fixtures data path, by default @tests\unit\fixtures\data

return [
    [
        'name' => 'Chase',
        'login' => 'lmayert',
        'email' => 'strosin.vernice@jerde.com',
        'auth_key' => 'K3nF70it7tzNsHddEiq0BZ0i-OU8S3xV',
        'password' => '$2y$13$WSyE5hHsG1rWN2jV8LRHzubilrCLI5Ev/iK0r3jRuwQEs2ldRu.a2',
    ],
    [
        'name' => 'Celestine',
        'login' => 'napoleon69',
        'email' => 'aileen.barton@heaneyschumm.com',
        'auth_key' => 'dZlXsVnIDgIzFgX4EduAqkEPuphhOh9q',
        'password' => '$2y$13$kkgpvJ8lnjKo8RuoR30ay.RjDf15bMcHIF7Vz1zz/6viYG5xJExU6',
    ],
];

如果我們正在使用將資料載入資料庫的夾具,那麼這些列將應用於 users 表。如果我們正在使用 nosql 夾具,例如 mongodb 夾具,那麼這些資料將應用於 users mongodb 集合。為了了解有關實作各種載入策略以及更多資訊,請參閱官方 文件。上面的夾具範例是由 yii2-faker 擴充套件自動產生的,請在這些 章節 中閱讀更多相關資訊。夾具類別名稱不應為複數。

載入夾具

夾具類別應以 Fixture 作為後綴。預設情況下,夾具將在 tests\unit\fixtures 命名空間下搜尋,您可以使用組態或命令選項來變更此行為。您可以透過在名稱前指定 - 來排除某些夾具,例如 -User,以進行載入或卸載。

要載入夾具,請執行以下命令

注意:在載入資料之前,會執行卸載順序。通常,這會導致清除先前夾具執行插入的所有現有資料。

yii fixture/load <fixture_name>

必要的 fixture_name 參數指定將載入資料的夾具名稱。您可以一次載入多個夾具。以下是此命令的正確格式

// load `User` fixture
yii fixture/load User

// same as above, because default action of "fixture" command is "load"
yii fixture User

// load several fixtures
yii fixture "User, UserProfile"

// load all fixtures
yii fixture/load "*"

// same as above
yii fixture "*"

// load all fixtures except ones
yii fixture "*, -DoNotLoadThisOne"

// load fixtures, but search them in different namespace. By default namespace is: tests\unit\fixtures.
yii fixture User --namespace='alias\my\custom\namespace'

// load global fixture `some\name\space\CustomFixture` before other fixtures will be loaded.
// By default this option is set to `InitDbFixture` to disable/enable integrity checks. You can specify several
// global fixtures separated by comma.
yii fixture User --globalFixtures='some\name\space\Custom'

卸載夾具

要卸載夾具,請執行以下命令

// unload Users fixture, by default it will clear fixture storage (for example "users" table, or "users" collection if this is mongodb fixture).
yii fixture/unload User

// Unload several fixtures
yii fixture/unload "User, UserProfile"

// unload all fixtures
yii fixture/unload "*"

// unload all fixtures except ones
yii fixture/unload "*, -DoNotUnloadThisOne"

類似的命令選項,例如:namespaceglobalFixtures 也可以應用於此命令。

全域設定命令

雖然命令列選項允許我們即時設定夾具命令,但有時我們可能想要一次性設定命令。例如,您可以如下設定不同的夾具路徑

'controllerMap' => [
    'fixture' => [
        'class' => 'yii\console\controllers\FixtureController',
        'namespace' => 'myalias\some\custom\namespace',
        'globalFixtures' => [
            'some\name\space\Foo',
            'other\name\space\Bar'
        ],
    ],
]

自動產生夾具

Yii 也可以根據某些範本為您自動產生夾具。您可以使用不同的語言和格式產生具有不同資料的夾具。此功能由 Faker 函式庫和 yii2-faker 擴充套件完成。請參閱擴充套件 指南 以取得更多文件。

總結

在上面,我們描述了如何定義和使用夾具。下面我們總結了執行資料庫相關單元測試的典型工作流程

  1. 使用 yii migrate 工具將您的測試資料庫升級到最新版本;
  2. 執行測試案例
    • 載入夾具:清除相關的資料庫表並使用夾具資料填充它們;
    • 執行實際測試;
    • 卸載夾具。
  3. 重複步驟 2,直到所有測試完成。

發現錯字或您認為此頁面需要改進?
在 github 上編輯 !