Laravel多数据库PHPUnit

12

我正在开发一个支持多个数据库访问的应用程序,并希望使用PHPUnit测试它。我的当前方法是在config\databases.php中拥有多个连接(mysql、mysql2、mysql3),因此我可以在env文件中为它们提供不同的访问方式。因此,模型已定义了$connection变量。在我的第一个功能测试中,我想访问一个页面,只看到我在工厂中提供的数据,以便开始工作。在我的phpunit.xml文件中,我指定了DB_CONNECTIONsqlite,对于每个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没有解析内存值。如有任何建议,将不胜感激。 谢谢。


你能否请发一些有关代码(测试和配置)的相关内容? - ka_lin
你需要发布你的数据库配置文件,因为我假设你进行了一些重大修改,考虑到使用了 DB_DATABASE_1DB_DATABASE_2DB_DATABASE_3 而不仅仅是 DB_DATABASE - Devon
已添加 .env 文件。谢谢 :) - Morpheus_ro
@Devon,只是为了澄清,请访问此网址-> https://laracasts.com/discuss/channels/laravel/access-another-db-in-the-service-provider - Morpheus_ro
是的,.env 文件并没有帮助,因为它只是设置了 ENV,而没有使用它。你的问题在于你在模型中覆盖了连接,所以当你在测试中使用模型时,你的连接不会使用 sqlite。 - Devon
显示剩余2条评论
3个回答

20

我遇到了同样的问题,但是在Twitter上得到了Adam Wathan的帮助后解决了。

这是我做的:

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';
    }
    ...
}

这个解决方案可能对我有帮助。但是你是否解决了像你在 Twitter 对话中提到的与 Adam Wathan 的关系问题呢?因为我也在遭受这种问题。 - Didi Halim
我不认为我这样做了。我相当确定我最终只是使用单个数据库进行测试。 - Curtis Blackwell

-1
为了解决类似的问题,我在模型类上使用了一个特征。
在我的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,
    ],

我会为我的每个连接创建一个trait,以设置连接并将它们包含在相关的模型中。例如,如果User模型需要使用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';
        }
    }
}

如果您在测试中使用迁移,我还必须在迁移文件中采用类似的方法,并为每个连接使用一个 trait。
对于 mysql_connection_a,我创建了一个类似下面的 trait 来覆盖 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)
            {

1
最好不要使用 env() 助手函数,因为它会破坏配置缓存 [参考]。相反,您可以使用 config('app.env') - Curtis Blackwell

-1

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

在phpunit.xml的<php>部分中,这应该足够(假设您没有修改sqlite连接):

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接