我目前正在尝试在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));
}
}
答案 0 :(得分:1)
请勿在测试用例中覆盖__construct()
。
测试用例在早期阶段实例化,并且还依赖于您未调用的PHPUnit_Framework_TestCase
constructor。此时DB
的自动加载器可能尚未初始化。
使用setUp()
代替,在每次测试之前调用它,并且是为了这种初始化而做的:
protected function setUp()
{
$this->repository = new UserRepository();
}