CakePHP 单元测试只工作一次,然后我必须重置数据库

CakePHP unit tests only work once, then I have to reset database

我正在尝试让我的团队开始为我们的应用程序进行一些单元测试。该应用程序基于 CakePHP 构建。

首先,我正在为我们的用户构建测试 table。我有以下 Fixture 来创建一个用户供我测试:

namespace App\Test\Fixture;

use Cake\TestSuite\Fixture\TestFixture;

class UsersFixture extends TestFixture
{
      public $connection = 'test';

      public $import = ['table' => 'users'];

      public $records = [
          [
              'username' => 'TestPass',
              'password' => '',
              'email' => 'TestPass@example.com',
              'status' => 'active',
              'created' => '2015-11-04 12:00:00',
              'last_logindate' => null,
              'registration_country' => 'AU',
              'system_user' => 0
          ]
      ];
}

我还有一个 table:

的测试用例
namespace App\Test\TestCase\Model\Table;

use App\Model\Table\UsersTable;
use Cake\ORM\TableRegistry;
use Cake\TestSuite\TestCase;

/**
 * App\Model\Table\UsersTable Test Case
 */
class UsersTableTest extends TestCase
{

    /**
     * Fixtures
     *
     * @var array
     */
    public $fixtures = [
        'app.Users'
    ];

    /**
     * setUp method
     *
     * @return void
     */
    public function setUp()
    {
        parent::setUp();
        $config = TableRegistry::exists('Users') ? [] : ['className' => 'App\Model\Table\UsersTable'];
        $this->Users = TableRegistry::get('Users', $config);
    }

    /**
     * tearDown method
     *
     * @return void
     */
    public function tearDown()
    {
        unset($this->Users);

        parent::tearDown();
    }
    // ...
}

我第一次 运行 这个测试它完美地工作。如果我再次尝试 运行,则会收到以下错误:

Sebastian Bergmann 和贡献者的 PHPUnit 4.8.27。

Warning Error: Fixture creation for "users" failed "SQLSTATE[42000]: Syntax error or access violation: 1101 BLOB/TEXT column 'status' can't have a default value" in [/path-to-app/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php, line 232]

Exception: Unable to insert fixtures for "App\Test\TestCase\Model\Table\UsersTableTest" test case. SQLSTATE[42S02]: Base table or view not found: 1146 Table 'carebook_test.users' doesn't exist in [/path-to-app/vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureManager.php, line 253]

我摆脱这个错误的唯一方法似乎是删除我的数据库,重新创建它,然后再次 运行 我的迁移。之后测试将再次 运行 成功,然后再次中断。

我做错了什么?

编辑:这似乎是因为一旦测试结束,table 就会被删除。但是如果 table 不存在,测试不会自动创建它,所以测试只有 运行 一次。我想知道是否有办法使 table 得到 t运行cated 而不是丢弃。或者,如果 table 不存在,则 Fixtures 将创建它。现在对这意味着如何工作有些困惑,因为我预计这个问题会影响到每个人。

EDIT2:我发现 CakePHP 确实打算创建 tables 如果它们不存在。我的问题是我的专栏是一个 ENUM,而 CakePHP Fixtures 不支持枚举列,所以它将它作为一个文本列。枚举列可以有默认值(我的有)但文本列不能。所以我想我必须弄清楚如何让 CakePHP 接受枚举列。

So I think I have to figure out how to make CakePHP accept enum columns.

是的。 CakePHP3 默认不支持枚举,因为它们不能在所有支持的数据库系统中工作。使用 Enum Plugin 获得枚举支持。

问题是 CakePHP 的 PHPUnit 扩展 类 添加了在测试 运行 之后删除测试表的功能。在测试套件的下一个 运行 中,Fixtures 用于重新创建表。

这种行为对我不起作用,因为我的数据库表包含枚举列。 CakePHP 不支持 ENUM 列,而是将它们视为文本列。这意味着当重新创建表时,它们有 TEXT 列而不是 ENUM 列。

这本来没问题,除了我的 ENUM 列有默认值,并且在 Windows MySQL 上尝试在 TEXT 列上设置默认值会导致错误。这绊倒了 CakePHP 的测试 运行ner 并阻止了我的测试 运行ning。

我和一位同事一起为 CakePHP 创建了一个插件,它允许它与 ENUM 列一起正常工作。此插件目前尚未公开,但我们计划在工作不忙时将其作为开源软件发布。

我想您会发现只要枚举字段在您的测试中不起作用,就可以忽略枚举问题。

缺少 table 错误是由于 DBO 驱动程序堆栈中的 'new' 缓存功能造成的。 DBO 会记住启动时出现的 tables,默认情况下不识别动态创建的 tables。

您可以禁用 tables 的缓存:

    public function setUp()
    {
        parent::setUp();
        $this->Users = ClassRegistry::init('Users');
        $this->Users->setDataSource('test2');
        $this->Users->cacheSources = false;
    }