为什么在Laravel构造函数中访问Facade失败?

时间:2016-04-03 10:00:01

标签: php laravel laravel-5 phpunit laravel-facade

我目前正在尝试在Laravel中实现存储库模式。

我有一个接口,声明了成为有效存储库所需的最小方法。

<?php

namespace App\Repositories;

interface RepositoryInterface
{
    public function all();

    public function create($entity);

    public function update($entity);

    public function find($id);

    public function delete($entity);
}

我有一个抽象类,表示我的存储库上的接口方法,如下所示:

namespace App\Repositories;

use DB;

abstract class DbRepository
{
    public function all()
    {
        return DB::table($this->tableName)->get();
    }

    public function create($user)
    {
        return $user->save();
    }

    public function update($user)
    {
        return $user->update();
    }

    public function find($id)
    {
        return DB::table($this->tableName)->where('id', $id)->first();
    }

    public function delete($user)
    {
        return $user->delete();
    }
}

实现接口的UserRepository并从抽象类继承,如下所示:

namespace App\Repositories;

use App\Models\User;

class UserRepository extends DbRepository implements RepositoryInterface
{

    public $tableName;

    public function __construct($tableName = 'users')
    {
        $this->tableName = $tableName;
    }

    /**
     * Override the parent find method, as we want to return an instance of App\Models\User instead of stdClass
     * @param $id
     * @return mixed
     */
    public function find($id)
    {
        return User::where('id', $id)->first();
    }
}

以上所有内容均正常,我的单元测试通过。但是,我认为将当前数据库表保存为存储库的抽象实现的属性会很好,所以我重构了类看起来像这样:

abstract class DbRepository implements RepositoryInterface
{
    private $table;

    public function __construct()
    {
        $this->table = DB::table($this->tableName);
    }

    public function all()
    {
        return $this->table->get();
    }
    # etc, etc...

然后确保从Repository的构造函数调用抽象类'构造函数:

public function __construct($tableName = 'users')
{
    $this->tableName = $tableName;
    parent::__construct();
}

执行此操作后,我收到以下错误,在运行PhpUnit时无法修复Error: Class 'DB' not found

我知道这个错误与我试图重构的方式有关。我相信这与尝试在抽象类的构造函数中访问DB Facade有关(因为在同一个类中的其他方法中访问DB很好)。任何解释都会非常感激 - 我很好奇为什么它不起作用。

我已将它恢复为原始代码(这很好,真的)并且测试再次通过!

哦,如果你想看看我的测试,这里他们是:

namespace Tests\Repositories;

use TestCase;
use App\Repositories\UserRepository;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class UserRepositoryTest extends TestCase
{
    use DatabaseMigrations;

    private $repository;

    public function __construct()
    {
        $this->repository = new UserRepository();
    }

    public function newUser()
    {
        return new User([
            'name' => 'Joe',
            'username' => 'joe',
            'password' => bcrypt('password'),
            'email' => 'joe@apple.com'
        ]);
    }

    public function test_all_method_returns_all_users()
    {
        $this->assertNotNull($this->repository->all());
    }

    public function test_create_user()
    {
        $this->assertTrue($this->repository->create($this->newUser()));
    }

    public function test_update_user()
    {
        // Arrange
        $user = $this->newUser();

        // Act
        $this->repository->create($user);
        $user->name = 'Jack';

        // Assert
        $this->assertTrue((integer)$this->repository->update($user) === 1);
    }

    public function test_delete_user()
    {
        // Arrange
        $user = $this->newUser();

        // Act
        $this->repository->create($user);

        // Assert
        $this->assertTrue((integer)$this->repository->delete($user) === 1);
    }

    public function test_find_user()
    {
        // Arrange
        $user = $this->newUser();

        // Act
        $this->repository->create($user);

        // Assert
        $this->assertInstanceOf(User::class, $this->repository->find($user->id));
    }
}

1 个答案:

答案 0 :(得分:1)

请勿在测试用例中覆盖__construct()

测试用例在早期阶段实例化,并且还依赖于您未调用的PHPUnit_Framework_TestCase constructor。此时DB的自动加载器可能尚未初始化。

使用setUp()代替,在每次测试之前调用它,并且是为了这种初始化而做的:

protected function setUp()
{
    $this->repository = new UserRepository();
}