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,您将看到setUpBeforeClasssetUp 方法之前运行,并且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;

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

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 中运行单元测试

如何在 laravel 5.5 中运行 phpunit

在 Laravel 5.5 中测试授权策略时遇到问题

Laravel 5.5 中 PHP 单元测试中的类验证器错误

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