Laravel多个数据库PHPUnit [重复]

Posted

技术标签:

【中文标题】Laravel多个数据库PHPUnit [重复]【英文标题】:Laravel multiple databases PHPUnit [duplicate] 【发布时间】:2017-11-07 14:10:07 【问题描述】:

我正在开发一个具有多个数据库访问权限的应用程序,我想用它进行 phpUnit 测试。我目前的方法是在config\databases.php 中拥有多个连接(mysql、mysql2、mysql3),这样我就可以在 env 文件中为所有这些连接提供不同的访问权限。因此,模型定义了$connection 变量。在我的第一个功能测试中,我想访问一个页面并查看我在工厂中提供的数据,所以只是为了让事情开始。在我的phpunit.xml 文件中,我已将DB_CONNECTION 指定为sqlite,并且为每个MySql 设置指定value=":memory:"

稍后编辑

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="CACHE_DRIVER" value="array"/>
    <env name="SESSION_DRIVER" value="array"/>
    <env name="QUEUE_DRIVER" value="sync"/>
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE_1" value=":memory:"/>
    <env name="DB_DATABASE_2" value=":memory:"/>
    <env name="DB_DATABASE_3" value=":memory:"/>
</php>

所以上面你可以从PHPUnit中找到相关代码。

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db1
DB_USERNAME=xxx
DB_PASSWORD=xxx

DB_HOST_2=127.0.0.1
DB_PORT_2=3306
DB_DATABASE_2=db2
DB_USERNAME_2=xxx
DB_PASSWORD_2=xxx

DB_HOST_2=127.0.0.1
DB_PORT_2=3306
DB_DATABASE_3=db3
DB_USERNAME_3=xxx
DB_PASSWORD_3=xxx

我遇到的问题是,当我运行测试时,我有这个错误 -> PDOException: SQLSTATE[HY000] [1049] Unknown database ':memory:'.

所以不知何故 Laravel 没有解析内存值。任何建议将不胜感激。 谢谢

【问题讨论】:

你的每一个mysql设置为value=:memory:是什么意思? 能否请您发布一些相关代码(测试和配置)? 您需要发布您的数据库配置文件,因为我假设您在考虑使用DB_DATABASE_1DB_DATABASE_2DB_DATABASE_3 而不仅仅是DB_DATABASE 时进行了一些重大修改。 添加了 .env 文件。谢谢你:) @Devon,只是为了澄清一下这个 url -> laracasts.com/discuss/channels/laravel/… 【参考方案1】:

我也遇到了同样的问题,但我用一些 help from Adam Wathan on Twitter 解决了问题。

这就是我所做的:

phpunit.xml:

<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="DB_CONNECTION_ACTIVITY_LOG" value="sqlite"/>
<env name="DB_DATABASE_ACTIVITY_LOG" value=":memory:"/>

config/database.php:

'sqlite' => [
    'driver' => 'sqlite',
    'database' => env('DB_DATABASE', database_path('database.sqlite')),
    'prefix' => '',
],

'mysql' => [
    'driver' => env('DB_CONNECTION', 'mysql'),
    'host' => env('DB_HOST', '127.0.0.1'),
    'port' => env('DB_PORT', '3306'),
    'database' => env('DB_DATABASE', 'forge'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'unix_socket' => env('DB_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

'mysql-activity-log' => [
    'driver' => env('DB_CONNECTION_ACTIVITY_LOG', 'mysql'),
    'host' => env('DB_HOST_ACTIVITY_LOG', '127.0.0.1'),
    'port' => env('DB_PORT_ACTIVITY_LOG', '3306'),
    'database' => env('DB_DATABASE_ACTIVITY_LOG', 'forge'),
    'username' => env('DB_USERNAME_ACTIVITY_LOG', 'forge'),
    'password' => env('DB_PASSWORD_ACTIVITY_LOG', ''),
    'unix_socket' => env('DB_SOCKET_ACTIVITY_LOG', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

.env:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my-app
DB_USERNAME=root
DB_PASSWORD=

DB_CONNECTION_ACTIVITY_LOG=mysql-activity-log
DB_HOST_ACTIVITY_LOG=127.0.0.1
DB_PORT_ACTIVITY_LOG=3306
DB_DATABASE_ACTIVITY_LOG=my-app
DB_USERNAME_ACTIVITY_LOG=root
DB_PASSWORD_ACTIVITY_LOG=

此外,对于没有达到 PDOException 的任何人,请确保也在您的迁移/模型中设置连接。

database/migrations/my_migration.php:

Schema::connection(env('DB_CONNECTION_ACTIVITY_LOG', 'mysql'))->create(...);

app/MyModel.php:

class MyModel extends Model

    public function __construct($attributes = [])
    
        parent::__construct($attributes);
        $this->connection = config('app.env') === 'testing' ? 'sqlite' : 'mysql-activity-log';
    
    ...

【讨论】:

这个解决方案可能对我有帮助。但是你有没有解决你在推特对话中提到的与亚当·沃森的关系问题?因为我也深受其害。 我想我没有。我很确定我最终只是用一个数据库进行了测试。【参考方案2】:

很难解码您实际放置 :memory: 值的位置。

在 phpunit.xml &lt;php&gt; 部分,这应该足够了(假设你没有修改 sqlite 连接):

<php>
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE" value=":memory:"/>
</php>

【讨论】:

【参考方案3】:

为了解决类似的问题,我在模型类上使用了一个特征。

在我的 phpunit.xml 我有这段代码

<env name="DB_CONNECTION" value="sqlite_testing"/>
<env name="DB_DATABASE" value=":memory:"/>```

在我的 config/database.php 文件中,我为每个数据库设置了连接,并为测试设置了 sqlite_testing 连接

'sqlite_testing' => [
    'driver' => 'sqlite',
    'database' => ':memory:',
    'prefix' => '',
],

'mysql_connection_a' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],

'mysql_connection_b' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE_B', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],

'mysql_connection_c' => [
        'driver' => 'mysql',
        'host' => env('DB_HOST', '127.0.0.1'),
        'port' => env('DB_PORT', '3306'),
        'database' => env('DB_DATABASE_C', 'forge'),
        'username' => env('DB_USERNAME', 'forge'),
        'password' => env('DB_PASSWORD', ''),
        'unix_socket' => env('DB_SOCKET', ''),
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'strict' => true,
        'engine' => null,
    ],

然后我为我的每个连接创建一个特征来设置连接并将它们包含在相关模型中。例如如果用户模型需要使用 mysql_connection_a 我会在模型中使用 ConnectionATrait

use App\Traits\ConnectionATrait;

class User extends Authenticatable

     use Notifiable, ConnectionATrait;

然后特征看起来像这样

trait ConnectionATrait

    /**
    * The database table used by the model.
    *
    * @var string
    */

    public function __construct(array $attributes = [])
   
        parent::__construct($attributes);
        if (env('APP_ENV') != 'testing') 
            $this->connection = 'mysql_connection_a';
        else
            $this->connection = 'sqlite_testing';
        
    

如果您在测试中使用迁移,我还必须在迁移文件中执行类似的方法,并为每个连接使用一个特征。

对于 mysql_connection_a,我创建了一个如下所示的特征,它覆盖了 getConnection 方法:

trait ConnectionAConnectionTrait

    /**
    * Get the migration connection name.
    *
    * @return string
    */
    public function getConnection()
    
        if (env('APP_ENV') != 'testing') 
            return 'mysql_connection_a';
        
        return 'sqlite_testing';
    

然后在迁移中它看起来像这样

use Database\migrations\traits\ConnectionAConnectionTrait;

class CreateUsersTable extends Migration 

     use ConnectionAConnectionTrait;

     /**
     * Run the migrations.
     *
     * @return void
     */
     public function up()
     
         Schema::connection($this->getConnection())
            ->create('users', function(Blueprint $table)
            

【讨论】:

最好不要使用env() 助手,因为它会破坏配置缓存[reference]。相反,您可以使用config('app.env')

以上是关于Laravel多个数据库PHPUnit [重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 Laravel 8 中运行多个 PHPUnit 测试时出错

Laravel - 一次多个数据库[重复]

Laravel 5:处理多个连接和测试

看不到响应获取请求 laravel phpunit

Laravel 5.5:PHPUnit(带覆盖)不喜欢来自多个文件的路由并抛出“尚未设置外观根”。没有报道它是绿色的

使用 phpunit 进行 Laravel 测试