SQLSTATE [23000]通过添加虚拟测试

时间:2019-05-09 01:06:42

标签: laravel phpunit

每当我分别运行它们时,我的测试都达到绿色状态,但是当我同时运行它们时,在第一次测试中都达到了SQLSTATE [23000]。第一个测试是我之前进行过的对应用程序有意义的测试,第二个是您可以看到的虚拟测试。

我已经恢复了错误消息,因为它显示了来自laravel的很多类,但是它指向第27行('user_id'=> 1)。

测试

<?php

namespace Tests\Unit;

use App\User;
use App\Tournament;
use Tests\TestCase;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class TournamentTest extends TestCase
{
    /**
     * A basic unit test example.
     *
     * @return void
     */
    use RefreshDatabase;

    protected function setUp() : void
    {
        parent::setUp();
        $this->withoutExceptionHandling();
        factory(User::class)->create();
        factory(Tournament::class)->create([
            'user_id' => 1
        ]);
    }

    /** @test **/
    public function index_page_shows_tournaments()
    {
        $user = User::first();

        $response = $this->actingAs($user)->get('/tournaments');

        $response->assertViewIs('tournaments.index');
    }

    /** @test **/
    public function create_tournament_shows_number_of_challengers()
    {
        $this->assertTrue(true);
    }
}

错误

There was 1 error:

1) Tests\Unit\TournamentTest::create_tournament_shows_number_of_challengers
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`torneio`.`tournaments`, CONSTRAINT `tournaments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)) (SQL: insert into `tournaments` (`user_id`, `name`, `interval`, `round`, `chal_num`, `status`, `updated_at`, `created_at`) values (1, Best Cross-group neutral support, 38, 1, 8, 1, 2019-05-09 00:56:44, 2019-05-09 00:56:44))

/home/tadeusvult/dev/torneio/tests/Unit/TournamentTest.php:27

Caused by
PDOException: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`torneio`.`tournaments`, CONSTRAINT `tournaments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`))

1 个答案:

答案 0 :(得分:0)

违反约束错误表明users表中没有id = 1的行。 SELECT * FROM users WHERE id = 1将返回空。

Laravel's document没有提及此行为-Rolling back a transaction will still increment the primary key。另请参见MySQL文档:“Lost” auto-increment values and sequence gaps

setUp()use RefreshDatabase;内部发生了什么:

protected function refreshTestDatabase()
{
    if (! RefreshDatabaseState::$migrated) {
        $this->artisan('migrate:fresh', ...);

        ...

        RefreshDatabaseState::$migrated = true;
    }
    $this->beginDatabaseTransaction();
}

https://github.com/laravel/framework/blob/5.8/src/Illuminate/Foundation/Testing/RefreshDatabase.php#L52

TournamentTest启动时,users将重置migrate:fresh表中的auto_increment,但不会在每种测试用例方法中重置。换句话说,当create_tournament_shows_number_of_challengers()运行时,由于回滚,index_page_shows_tournaments()中没有行,但是auto_increment仍返回2。

尝试打印出setUp()中的ID。最好还是不要使用硬编码的号码:

protected function setUp() : void
{
    parent::setUp();
    $this->withoutExceptionHandling();
    $user = factory(User::class)->create();

    var_dump($user->id); // see what's going on

    factory(Tournament::class)->create([
        'user_id' => $user->id // clearer intention
    ]);
}