在 Laravel 8.0 测试中刷新数据库时“没有活动事务”

Posted

技术标签:

【中文标题】在 Laravel 8.0 测试中刷新数据库时“没有活动事务”【英文标题】:"There is no active transaction" when refreshing database in Laravel 8.0 test 【发布时间】:2021-07-15 18:50:14 【问题描述】:

使用 php 8.0.2 和 Laravel 8.37.0,我正在运行测试,每次测试都应该刷新数据库数据,因为每个测试都有冲突的数据(由于独特的约束)。 使用带有 SQLite 的内存数据库,这是可行的,但是当我切换到 mysql (v8.0.23) 时,我得到下一个错误:

1) Tests\Feature\Controllers\AuthControllerTest::testSuccessLogin
PDOException: There is no active transaction

由于数据已插入且测试后未清除,因此之后的测试失败。

我要做的测试是:

<?php

namespace Tests\Feature\Controllers;

use App\Models\User;
use App\Models\User\Company;
use App\Repositories\UserRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AuthControllerTest extends TestCase

    use RefreshDatabase;

    protected array $connectionsToTransact = ['mysql'];

    public function testSuccessLogin(): void
    
        $this->artisan('migrate-data');

        /** @var User $user */
        $user = User::factory()->create([
            'email' => 'test@website.com'
        ]);

        $this->app->bind(UserRepository::class, function() use ($user) 
            return new UserRepository($user, new Company());
        );

        $loginResponse = $this->post('/api/login', [
            'email' => 'test@website.com',
            'password' => 'password'
        ]);

        $loginResponse->assertStatus(200);
        $loginResponse->assertJsonStructure([
            'data' => [
                'user' => [
                    'name',
                    'surname',
                    'email',
                    'abilities'
                ],
                'token',
            ]
       ]);
    

执行此测试并检查数据库后,数据仍然存在。有和没有protected array $connectionsToTransact = ['mysql']; 行给我的结果是一样的。

我的phpunit.xml-文件看起来像:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
     bootstrap="vendor/autoload.php"
     colors="true"
>
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">./app</directory>
        </include>
        <report>
            <html outputDirectory="reports/coverage"/>
        </report>
    </coverage>
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="mysql"/>
        <server name="DB_HOST" value="localhost"/>
        <server name="DB_DATABASE" value="mysql_test"/>
        <server name="DB_USERNAME" value="root"/>
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
    </php>
</phpunit>

这是一个已知问题吗?还是我错过了什么?

【问题讨论】:

尝试删除$connectionsToTransact 感谢您的回答,miken32。我之前尝试过,它仍然无法正常工作。检查源代码时,它为该数组中的所有连接设置了一个事务,所以有点奇怪。 RefreshDatabase 的测试中所做的一切总是在事务中完成,因此没有必要。错误消息意味着某些东西正在尝试关闭已经关闭的事务,所以我猜那里有一些冲突。 过去我尝试使用 RefreshDatabase 测试使用事务的代码时发生过这种情况。内部代码关闭事务似乎干扰了 RefreshDatabase 的事务。 MySQL 的Engine=MEMORY 对“事务”一无所知。仅限Engine=InnoDB 【参考方案1】:

问题在于您的测试包含隐式提交,因此结束了活动事务。

重新-

“只要我执行 CREATE 语句,我就会收到事务错误。” -

CREATE TABLE 等是statements that cause an implicit commit。

这反过来意味着RefreshDatabase trait 将不起作用,因为在事务关闭时无法回滚。

因此PDOException: There is no active transaction

这似乎是 php 8.0 的一个已知问题/抛出错误 - https://gitmemory.com/issue/laravel/framework/35380/734740942

【讨论】:

以上是关于在 Laravel 8.0 测试中刷新数据库时“没有活动事务”的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 8 和 Ajax - 将数据插入表中总是刷新加载

Laravel Dusk:迁移和种子测试数据库一次

laravel ajax 成功后如何刷新数据表?

在 Laravel 8 中刷新后重复数据

Laravel 5.1 - 每次刷新时会话重新生成

为啥 laravel 验证不显示错误