Fixtures 是测试中非常重要的一部分。他们的主要目的是建立一个固定/已知的环境状态以确保 测试可重复并且按照预期方式运行。

你可以使用 Fixtures 来确保用户DB表包含固定的数据。 你在运行一个测试之前加载一个或者多个 fixture object,并在结束后卸载他们。

配置:

Yii2.0 高级模板的 Fixtures 默认路径是在 common\fixtures 下,路径的配置是在 console\config\main.php 中配置的。

'controllerMap' => [
        'fixture' => [
            'class' => 'yii\console\controllers\FixtureController',
            'namespace' => 'common\fixtures',
          ],
    ],

编写Fixture类:

使用 Fixture,你需要创建一个新的 class 继承自 yii\test\Fixture 或者 yii\test\ActiveFixture 。前一个类对于一般用途的 Fixture 比较适合, 而后者则有一些增强功能专用于与数据库和 ActiveRecord 一起协作。

说明:

  1. Fixture 类的名称应该以 Fixture 字符作为后缀。
  2. yii\test\ActiveFixture 适用 SQL 数据库
  3. yii\mongodb\ActiveFixture 适用 Mongo DB
  4. yii\elasticsearch\ActiveFixture(从版本 2.0.2 开始)适用 Elasticsearch
  5. 可以使用 $tableName 或者 $modelClass 指定数据写入目标
  6. $dataFile 指定数据来源,如果未设置的话默认 FixturePath/data/TableName.php
  7. 如果未指定 $dataFile 数据来源,重载 getData() 方法也可以
  8. getData() 中 key user1,user2 为数据别名
  9. 你不需要特别的为自动增长(auto-incremental)的列指定数据, Yii 将会在 Fixture 被加载时自动的填充正确的列值到这些行中;或者你指定id值为固定值。
<?php

namespace common\fixtures;

use yii\test\ActiveFixture;

class UserFixture extends ActiveFixture
{
    // 先找 $tableName
    public $tableName = 'user';

    // 再找 modelClass 
    public $modelClass = 'common\models\User';

   // 指定数据来源,如果未设置的话默认 __DIR__.'/data/user.php'
    public $dataFile = __DIR__ . '/data/user_data.php';

    // 如果未指定 $dataFile 也可以在此方法中返回写入表中的数据
    public function getData()
    {
        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',
            ],
        ];
    }
    
}

Fixture 依赖:

一个 Fixture 可能依赖于其他的 Fixtures ,通过它的 yii\test\Fixture::$depends 来指定。 当一个 Fixture 被加载前,它依赖的 Fixture 会被自动的加载;同样,当某个 Fixture 被卸载后, 它依赖的 Fixtures 也会被自动的卸载。

比如一个 UserProfileFixture 可能需要依赖于 UserFixture, 因为 user profile 表包括一个指向 user 表的外键。那么, 这个依赖关系可以通过 yii\test\Fixture::$depends 属性来指定,比如如下:

namespace common\fixtures;

use yii\test\ActiveFixture;

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

编写数据来源文件:

默认情况下,Fixture 类会在其所在的目录下面的 data 子目录寻找相关的数据文件,也可在 $dataFile 指定数据的来源。

如上例中 $dataFile 指定为当前目录下的data目录 下 user_data.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',
            ],
        ];

或者在数据库中填好数据,然后导出JSON文件,上传至Fixture的data目录下。

<?php
$json = file_get_contents(__DIR__.'/user.json');

$data = json_decode($json, true);

return $data['RECORDS'];

Fixture的使用:

Yii 通过 yii fixture 命令行工具来支持 fixtures 操作

加载 Fixtures

命令格式

yii fixture/load <fixture_name>

必需参数 fixture_name 指定一个将被加载数据的 Fixture 名字。 你可以同时加载多个 Fixtures 。 以下是这个命令的正确格式:

// 加载 `User` fixture
yii fixture/load User

// 与上面相同,因为 “fixture” 命令的默认动作是“加载”
yii fixture User

// 加载几个 fixtures
yii fixture User UserProfile

// 加载所有 fixtures
yii fixture/load "*"

// 与上面相同
yii fixture "*"

// 加载所有 fixtures 除了这些
yii fixture "*" -DoNotLoadThisOne

// 加载 fixtures, 但在不同的命名空间中搜索它们。默认命名空间是:common\fixtures。
yii fixture User --namespace='alias\my\custom\namespace'

// 加载全局 fixture `some\name\space\CustomFixture` 在加载其他 fixtures 之前.
// 默认情况下,此选项设置为 `InitDbFixture` 以禁用/启用完整性检查。您可以用用逗号分离来
// 指定几个全局 fixtures。
yii fixture User --globalFixtures='some\name\space\Custom'

卸载 Fixtures

运行如下命名去卸载 Fixtures:

// 卸载 User fixture,默认情况下它将清除 fixture 存储(例如“用户”表,或“用户”集合如果这是 mongodb fixture)。
yii fixture/unload User

// 卸载几个 fixtures
yii fixture/unload User,UserProfile

// 卸载所有 fixtures
yii fixture/unload "*"

// 卸载所有 fixtures 除了这些
yii fixture/unload "*" -DoNotUnloadThisOne

全局Fixtures配置:

Fixtures有一个默认全局配置 yii\test\InitDbFixture,全局配置格下如下:

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

自动生成 Fixtures:

Yii 还可以为你自动生成一些基于一些模板的 Fixtures。 你能够以不同语言格式用不同的数据生成你的 Fixtures。 这些特征由 Faker 库和 yii2-faker 扩展完成。 关注 guide 扩展获取更多的文档。

总结:

在上面,我们描述了如何定义和使用 Fixture,在下面,我们将总结出一个 标准地运行与 DB 有关的单元测试的规范工作流程:

  1. 使用 yii migrate 工具来让你的测试数据库更新到最新的版本;
  2. 运行一个测试:
    • 卸载 yii fixture/unload 清空所有的相关表数据
    • 加载 yii fixture/load 填充数据
    • 执行真实的测试用例
    • 卸载 yii fixture/unload 清空所有的相关表数据
  3. 重复步骤 2 直到所有的测试结束。