Laravel测试不会在每次测试后回滚事务

pat*_*ato 6 testing pdo transactions mariadb laravel

我的测试使用该特征RefreshDatabase在开始测试之前“新鲜”迁移,并对每种测试方法使用事务。

迁移工作正常,但是事务根本无法正常工作。

我尝试公开我的设置:

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

我的setUp方法:

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

    Queue::fake();
}
Run Code Online (Sandbox Code Playgroud)

您可以在此要点中找到完整的测试类和测试基类:https : //gist.github.com/patriziotomato/e25de1e160dace08edefa682b64bd150

我已经尝试调试,并且还开始进行PDO操作并回滚事务,因此laravel代码似乎试图进行事务处理并回滚,但是在我的测试中没有任何影响。

我想知道还有什么地方可能出问题

Gle*_*nov 5

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

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

public function tearDown()
{
    DB::rollback();
    parent::tearDown();
}
Run Code Online (Sandbox Code Playgroud)

  • 就我而言,我猜由于“RefreshDatabase”,这不起作用:“Doctrine\DBAL\Driver\PDOException:SQLSTATE[42000]:语法错误或访问冲突:1305 SAVEPOINT trans2 不存在” (3认同)

Bar*_*kes 5

我自己也遇到了同样的问题,使用类似的 MySQL 设置。我也尝试了上面安东尼的解决方案,我...1305 SAVEPOINT trans2 does not exist...也看到了同样的错误。

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

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

更新这个 Laracast 线程的 最佳答案实际上解释了事务操作在操作期间有一个隐式提交,并且在测试期间抛出事务堆栈。


Den*_*app 5

您可能正在使用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 的相关回答:


Ken*_*rna 1

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

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

class SomeTest extends TestCase {

    use DatabaseTransactions;

public some_assertion_method()
{
    ...
}
Run Code Online (Sandbox Code Playgroud)