如何在没有夹具的情况下在 Yii PHPUnit 测试中创建模型对象?

How to create a Model object in Yii PHPUnit test without a fixture?

我正在为我的 Yii 应用程序编写 PHPUnit 测试。我读 here:

Tip: Having too many fixture files could increase the test time dramatically. For this reason, you should only provide fixture files for those tables whose content may change during the test. Tables that serve as look-ups do not change and thus do not need fixture files.

我确实有一个很大的夹具(180 条记录,加载时间>20 秒),仅用作查找。但是,我确实需要轻松地将它从关联数组转换为模型对象,就像您通常可以使用下面的固定语法一样。提示建议还有一种方法可以在不使用夹具的情况下创建模型对象,但没有提及 如何 这是完成的。有人可以帮忙吗?

使用夹具创建模型对象:

// tests/fixtures/Order.php
return array(
    'row_id' => array(
        'id' => 1,
        'name' => 'hello',
    )
)

// tests/unit/AbcTest.php
public $fixtures = array(
    'orders' => 'Order',
)

public test_abc()
{
    $order = $this->orders('row_id');
    ....
}

是的,有可能达到你想要的。
例如:我有型号 品牌 有自己的夹具:

<?php
// protected/tests/fixtures/brand.php

return [
    1 => [
        'name' => 'Lexus',
        'country' => 'JPN',
    ],
    2 => [
        'name' => 'Acura',
        'country' => 'JPNE',
    ],
];

我有下一个代码:

    $brand = new Brand;
    $allBrands = $brand->findAll();

此代码将 return 包含 2 个 CActiveRecord 对象的数组。以及我们需要的一切 - 它只是用 2 个 CActiveRecord 对象构建相同的数组:

public function testGetAllAvailableBrands()
{
    // Get brands from fixture.
    $brand = new Brand;
    $allBrandsFromFixture = $brand->findAll();
    // Generate brands.
    $lexus = new Brand;
    $lexus->scenario = 'update';
    $lexus->name = 'Lexus';
    $lexus->country = 'JPN';
    $lexus->id = 1;
    $lexus->setPrimaryKey(1);
    $lexus->setIsNewRecord(false);
    $allBrandsGeneratedAtRuntime[] = $lexus;
    $acura = new Brand;
    $acura->scenario = 'update';
    $acura->name = 'Acura';
    $acura->country = 'JPNE';
    $acura->id = 2;
    $acura->setPrimaryKey(2);
    $acura->setIsNewRecord(false);
    $allBrandsGeneratedAtRuntime[] = $acura;
    // Brands from fixture should be equals to generated brands.
    $this->assertEquals($allBrandsFromFixture, $allBrandsGeneratedAtRuntime);
}

这个测试会是绿色的,因为我们的牌子一模一样。你猫试试这样的东西。

但我认为原生 yii fixtures 看起来好多了,为了避免增加测试时间你应该使用 .init.php 文件...

另一种选择:
当您创建 db 迁移 时,您应该将其应用于 production db 和 test db 此外你应该用测试数据填充测试表。

这种方法的好处:

  1. 您将 运行 填充 sql 一次(不像 fixture - 每次调用测试)。
  2. 您的测试将执行得很快,因为数据库已准备就绪。
  3. 当您提交需要使用数据库中的新数据进行新测试的新功能时 - 您创建数据库迁移,它只会执行一次,在 明确的方式。

例如:

<?php

class m150608_110143_init extends CDbMigration
{
    public function safeUp()
    {
        $sql1 = "
            CREATE TABLE brand (
                id INT AUTO_INCREMENT,
                name VARCHAR(100) NOT NULL DEFAULT '',
                country VARCHAR(50) NOT NULL DEFAULT '',
                PRIMARY KEY (id)
            );
        ";
        $sql2 = "
            INSERT INTO brand VALUES
                (null, 'aston martin', 'UK'),
                (null, 'audi', 'Germany'),
                (null, 'bmw', 'Germany'),
                (null, 'citroen', 'France'),
                (null, 'peugeot', 'France'),
                (null, 'porsche', 'Germany'),
                (null, 'toyota', 'Japan'),
                (null, 'ferrari', 'Italy')
            ;
        ";
        // Production db.
        $this->setDbConnection(Yii::app()->db);
        $this->execute($sql1);
        // Test db.
        $this->setDbConnection(Yii::app()->dbUnitTest);
        $this->execute($sql1);
        // Populate test db with fixtures.
        $this->execute($sql2);
        return true;
    }

    public function down()
    {
        $sql = 'DROP TABLE brand;';
        // Test db.
        $this->setDbConnection(Yii::app()->dbUnitTest);
        $this->execute($sql);
        // Production db.
        $this->setDbConnection(Yii::app()->db);
        $this->execute($sql);
        return true;
    }
}

并且在测试中您不必考虑固定装置。