Laravel 5.5 PHPunit 测试 - “尚未设置外观根。”
Posted
技术标签:
【中文标题】Laravel 5.5 PHPunit 测试 - “尚未设置外观根。”【英文标题】:Laravel 5.5 PHPunit Test - "A facade root has not been set." 【发布时间】:2018-03-09 05:30:48 【问题描述】:当我在 DB::Connection()->getPdo();
上执行 try/catch 时,我收到错误 尚未设置门面根。 我相信在我尝试之前,Schema
门面也会发生这种情况添加尝试/捕获。 tests 目录当然在 app 目录之外,我感觉它与此有关,但我没有成功弄清楚。
这是发生这种情况的测试类:
<?php
namespace Tests\Models;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
use App\Models\Discussion;
use App\User;
use Business\Database\Model;
use Illuminate\Database\Schema\Blueprint;
use Tests\TestCase;
class DiscussionModelTest extends TestCase
/**
* Create the tables this model needs for testing.
*/
public static function setUpBeforeClass()
try
DB::connection()->getPdo();
catch(\Exception $e)
die($e->getMessage());
Schema::create('discussions', function (Blueprint $table)
$table->integer('id');
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
);
Schema::create('users', function (Blueprint $table)
$table->integer('id');
);
【问题讨论】:
在单元测试中构建模式有点令人担忧。通常您希望预先构建一个数据库,然后使用Illuminate\Foundation\Testing\DatabaseTransactions
trait 确保在单元测试完成时退出。
【参考方案1】:
问题是您不能在 setUpBeforeClass 中执行此操作,因为很多事情都是在 setUp
方法中运行的。如果您查看this order of run,您将看到setUpBeforeClass
在setUp
方法之前运行,并且TestCase 类在setUp
方法中做了很多事情。它看起来像这样:
protected function setUp()
if (! $this->app)
$this->refreshApplication();
$this->setUpTraits();
foreach ($this->afterApplicationCreatedCallbacks as $callback)
call_user_func($callback);
Facade::clearResolvedInstances();
Model::setEventDispatcher($this->app['events']);
$this->setUpHasRun = true;
所以你应该做的是用你自己的实现创建自己的setUp
和tearDown
方法,如下所示:
protected function setUp()
parent::setUp();
// your code goes here
protected function tearDown()
parent::tearDown();
// your code goes here
【讨论】:
我查看了基础测试的 setUp 函数,它实际上是一个空函数。 @JustinAnthony 你看过Illuminate\Foundation\Testing\TestCase
类吗?在这堂课中,你有 setUp
方法和我展示的内容
糟糕,我进入了该基金会的父级设置。走得太深了。实际上看起来就是这样做的,将我的 Schema 调用放入 setUp
而不是 setUpBeforeClass
。在此期间,我确实找到了另一个使用 Capsule
的解决方案。在这两种方法中,您认为哪种方法更好用?
我从未听说过胶囊。我将 setUp 用于此类事情,但通常没有必要手动创建表,因为您通常使用数据库特征从迁移中创建数据库模式。
我遇到了一个问题,我们正在使用更新版本的 mysql,我们使用 json 列类型,这与 sqlite 不兼容,所以我需要专门定制一个迁移子集供测试用。我想做到这一点,所以我每个测试套件只创建一次表,但在每次测试开始之前播种它们。必须在 setUp 中运行虚假迁移是否会导致测试时间显着延迟?【参考方案2】:
I get answer here
您不应该这样做,因为功能测试会扩展您的测试目录中的 TestCase 类,而不是 PHPUnit 的。
删除:
use PHPUnit\Framework\TestCase;
并将其替换为:
use Tests\TestCase;
【讨论】:
【参考方案3】:对于其他对我发现使用 Capsule 的其他方法感到好奇的人,这里是代码。这将适用于setUpBeforeClass()
和setUp()
。这可以而且应该更抽象,但这就是它的要点。
use Illuminate\Database\Capsule\Manager as Capsule;
class DiscussionModelTest extends TestCase
/**
* Create the tables this model needs for testing.
*/
public static function setUpBeforeClass()
$capsule = new Capsule;
$capsule->addConnection([
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
]);
$capsule->setAsGlobal();
$capsule->bootEloquent();
Capsule::schema()->create('discussions', function (Blueprint $table)
$table->integer('id');
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
);
Capsule::schema()->create('users', function (Blueprint $table)
$table->integer('id');
);
// Seed the faux DB
Model::unguard();
User::create([
'id' => 13
]);
Discussion::create([
'id' => 5,
'user_id' => 13
]);
【讨论】:
以上是关于Laravel 5.5 PHPunit 测试 - “尚未设置外观根。”的主要内容,如果未能解决你的问题,请参考以下文章
如何在 laravel 5.5 中使用 phpunit 测试中间件?
如何使用内存数据库中的 sqlite 在 laravel 5.5 中运行单元测试