在 Laravel PHPUnit 测试中使用内存中的 SQLite

Posted

技术标签:

【中文标题】在 Laravel PHPUnit 测试中使用内存中的 SQLite【英文标题】:Use in-memory SQLite in Laravel PHPUnit test 【发布时间】:2019-01-27 14:49:30 【问题描述】:

我正在尝试在我的新工作中运行一个 Laravel 项目。离开的开发人员在交接文件中没有说明如何启动和运行代码,其他人也不知道。

SQLite 数据库是使用:memory: 创建的,php artisan migrate 可以正常工作。

...
Migrating: 2016_06_01_000004_create_oauth_clients_table
Migrated:  2016_06_01_000004_create_oauth_clients_table
...

特征(标准 Laravel 代码)中的方法 beginDatabaseTransaction() 正在执行,但之后没有任何表存在。就好像正在创建数据库但没有执行迁移一样。

<?php

namespace Illuminate\Foundation\Testing;

trait DatabaseTransactions

    /**
     * Handle database transactions on the specified connections.
     *
     * @return void
     */
    public function beginDatabaseTransaction()
    
        $database = $this->app->make('db');

        foreach ($this->connectionsToTransact() as $name) 
            $database->connection($name)->beginTransaction();
        

        $this->beforeApplicationDestroyed(function () use ($database) 
            foreach ($this->connectionsToTransact() as $name) 
                $connection = $database->connection($name);

                $connection->rollBack();
                $connection->disconnect();
            
        );
    

测试代码(最后显示的指令失败):

<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Laravel\Passport\ClientRepository;

class PassportTest extends TestCase

    use DatabaseTransactions;

    public function test_basic_oauth_token_authentication()
      $clientRepository = new ClientRepository();
      $client = $clientRepository->createPersonalAccessClient(
          null, 'Test Personal Access Client', $this->baseUrl
      );

命令行:

vendor/bin/phpunit tests/Feature/PassPortTest

错误信息:

Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1 no such table: oauth_clients
Caused by  
Doctrine\DBAL\Driver\PDOException: SQLSTATE[HY000]: General error: 1 no such table: oauth_clients
Caused by
PDOException: SQLSTATE[HY000]: General error: 1 no such table: oauth_clients

如何确保表已作为每个测试的一部分创建?

【问题讨论】:

尝试在setUp函数中调用artisan migrate @DigitalDrifter 另一个网站建议在测试中首先调用Artisan::call('migrate');,但这没有效果。 TestCase 类中有什么额外的内容吗? 使用 RefreshDatabase 特征。 laravel.com/docs/5.6/… @DigitalDrifter 好的。使用RefreshDatabase 而不是DatabaseTransactions 让我克服了那个错误(到一个不相关的错误)。由于方法名称冲突,尝试use 会出现 PHP 错误。 【参考方案1】:

在您的 SQLite 配置中使用 :memory: 时有一个警告。您的命令行迁移所命中的内存位置测试试图与之交谈的内存位置相同。您的应用程序的每个实例基本上都会启动一个新的虚拟临时数据库。

你有两个选择。要么用显式文件名替换 :memory: 配置,要么让测试的 setUp() 方法实际启动 \Aritsan::call('migrate') 调用。不过我不推荐后者,因为它可能会很慢,而且我不完全确定如果您当时有交易活动,迁移实际上会坚持下去。

【讨论】:

【参考方案2】:

使用 RefreshDatabase 特征而不是 DatabaseTransactions 特征(如果您尝试在同一个类中同时使用这两个特征,它们会发生冲突)。

查看有关resetting the database after each test的文档。

【讨论】:

以上是关于在 Laravel PHPUnit 测试中使用内存中的 SQLite的主要内容,如果未能解决你的问题,请参考以下文章

PHPUnit 似乎没有运行 Laravel 迁移

如何使用内存数据库中的 sqlite 在 laravel 5.5 中运行单元测试

使用 phpunit.xml、.env.dusk.local 和 sqlite 内存数据库设置 Laravel 5.4 和 Dusk

在 laravel 4 中使用 phpunit 测试 POST

在 Laravel 中设置 PHPUnit 测试

如何在 laravel 5.5 中使用 phpunit 测试中间件?