【问题标题】:Laravel tests don't rollback transaction after each testLaravel 测试不会在每次测试后回滚事务
【发布时间】:2018-07-21 08:36:33
【问题描述】:

我的测试使用 trait RefreshDatabase 在开始测试之前“迁移新鲜”并为每种测试方法使用事务。

迁移工作正常,但事务根本不工作。

我尝试公开我的设置:

  • MariaDB 10.1 在 docker 容器中运行(我已经证明我的测试中使用的所有表都在 InnoDB 中,因此支持事务)
  • 基础测试类使用RefreshDatabase
  • 我尝试使用单独的连接与$connectionsToTransact 一起进行测试,并使用默认连接进行测试。交易也不行

我的设置方法:

protected function setUp()
{
    parent::setUp();

    Queue::fake();
}

您可以在此 Gist 中找到完整的 Test Class 和 Test 基类: https://gist.github.com/patriziotomato/e25de1e160dace08edefa682b64bd150

我已经尝试调试,并且还归结为 PDO 启动和回滚事务,所以看起来 laravel 代码尝试进行事务和回滚,但它对我的测试没有任何影响。

我需要想法还有什么可能出错的地方

【问题讨论】:

  • 您是否在需要时致电setUp()tearDown()
  • 将我的setUp() 方法添加到我原来的问题中
  • 你在开发一个包吗?为什么不使用sqlite 而不是适当的数据库?
  • 在最新版本的 Laravel 5.6 中修复了一个与测试中的 RefreshDatabase 相关的错误。尝试升级到最新版本的 5.6
  • 您指的是哪个修复程序?

标签: laravel testing pdo transactions mariadb


【解决方案1】:

您可能正在使用Model::truncate()

不幸的是,truncate() 与 MySQL 5.1.32 以来的事务不“兼容”。您可以 DROP 表,但不能在事务中 truncate()

http://dev.mysql.com/doc/refman/5.1/en/truncate-table.html

根据这个 URL,从 MySQL 5.1.32 开始,TRUNCATE TABLE 是 DDL 和 不像 DELETE 那样 DML。这意味着 TRUNCATE TABLE 将导致 事务块中间的隐式 COMMIT。所以,使用 DELETE FROM 在您需要清空而不是 TRUNCATE TABLE 的表上。

来自 StackOverflow 和 Laracasts 的相关答案:

【讨论】:

  • 否认你是英雄
  • DELETE FROM 是否像截断一样重置 ID 列?
  • delete兼容事务,只有truncate不兼容
【解决方案2】:

我自己也遇到了类似的 MySQL 设置问题。我还从上面尝试了 Anthony 的解决方案,我也看到了相同的 ...1305 SAVEPOINT trans2 does not exist... 错误。

在我的例子中,罪魁祸首是代码中的Model::truncate() 操作(用于重新导入命令)。不知何故,这似乎扰乱了 Laravel 的事务/回滚处理(或 MySQL 的?),导致上述错误。改用Model::all()->each->delete() 解决了我的问题。 (经过进一步测试,似乎我也无法重置 auto_increment 值,所以这就是问题所在......)

值得注意的是,如果使用内存数据库但使用 MySQL 设置可能不会发生这种情况,例如,如果恶意条目保持完整,很容易与即将进行的测试混淆,从而导致难以调试的错误,所以要小心... :)

更新 最佳答案on this Laracast thread实际上解释了事务操作在操作过程中有一个隐式提交,并且在测试过程中抛出了事务堆栈。

【讨论】:

  • 这可能取决于 Laravel 版本,但我认为 Model::all()->each->delete() 不会起作用。具体来说,each 是一个接受回调的函数,而不是一个属性,除非我弄错了。
【解决方案3】:

我也有同样的问题。从未找到确切原因,但有一个解决方法 - 手动启动和回滚事务:

public function setUp()
{
    parent::setUp();
    DB::beginTransaction();
}

public function tearDown()
{
    DB::rollback();
    parent::tearDown();
}

【讨论】:

  • 就我而言,我猜是因为RefreshDatabase 这不起作用:Doctrine\DBAL\Driver\PDOException : SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT trans2 does not exist
【解决方案4】:

要回滚测试文件中的事务,您可以使用DatabaseTransactions

...
use Illuminate\Foundation\Testing\DatabaseTransactions;
...

class SomeTest extends TestCase {

    use DatabaseTransactions;

public some_assertion_method()
{
    ...
}

【讨论】:

  • 嗨。 RefreshDatabase 也可以这样做,但在我的情况下它们不起作用。我也尝试了你的想法,但交易不想在这里工作:(
【解决方案5】:

更改文件 phpunit.xml

<php>
        <env name="DB_CONNECTION" value="mysq"/>
        <env name="APP_ENV" value="local"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="MAIL_DRIVER" value="array"/>
        <env name="SMS_DRIVER" value="array"/>
</php>

将此特征添加到测试文件:

use DatabaseTransactions;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-15
    • 1970-01-01
    • 2012-11-26
    • 2016-10-07
    • 2023-01-11
    • 1970-01-01
    • 2015-06-19
    • 1970-01-01
    相关资源
    最近更新 更多