Laravel 5.5 PHP 单元测试 - "A facade root has not been set."

Laravel 5.5 PHPunit Test - "A facade root has not been set."

当我在 DB::Connection()->getPdo(); 上执行 try/catch 时,我得到错误 A facade root has not been set. 我相信它发生在在我尝试添加 try/catch 之前,Schema 立面也是如此。 tests目录当然在app目录之外,我感觉跟那个有关系,但是我没弄清楚。

这是测试 class 发生这种情况的地方:

<?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');
        });
    }
}

问题是您不能在 setUpBeforeClass 中执行此操作,因为 setUp 方法中有很多内容 运行。如果您查看 this order of run,您会看到 setUpBeforeClasssetUp 方法之前是 运行,而 TestCase class 在 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;
}

所以您应该做的是使用您自己的实现创建自己的 setUptearDown 方法,如下所示:

protected function setUp()
{
   parent::setUp();
   // your code goes here
}

protected function tearDown()
{
   parent::tearDown();
   // your code goes here
}

如果其他人对我发现的使用 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
        ]);
    }
}

I get answer here

你不应该这样做,因为功能测试会扩展测试目录中的 TestCase class 而不是 PHPUnit 的。

删除:

use PHPUnit\Framework\TestCase;

并将其替换为:

use Tests\TestCase;