如何测试依赖于具有关系的 Eloquent 模型的类?
Posted
技术标签:
【中文标题】如何测试依赖于具有关系的 Eloquent 模型的类?【英文标题】:How to test a class which depends on an Eloquent model with relationships? 【发布时间】:2014-05-19 13:36:46 【问题描述】:为依赖于具有关系的 Eloquent 模型的类编写单元测试的最佳方法是什么?例如
真实对象(带数据库)。这很容易,但速度很慢。
真实对象(无数据库)。我可以创建一个新对象,但我看不到如何在不写入数据库的情况下设置相关模型。
模拟对象。我在使用 Mockery 和 Eloquent 模型时遇到了问题(例如,请参阅 this question)。
其他解决方案?
context:我使用 Laravel 和 Authority RBAC 进行访问控制。我想找到在单元测试中测试我的访问规则的最佳方法。这意味着我需要在测试期间将用户依赖项传递给授权。
【问题讨论】:
权宜之计是使用内存中的 SQLite 数据库进行测试。我认为默认情况下 Laravel 实际上会为您执行此操作,尽管您确实需要在设置时调用播种机。不知道它是否真的比 mysql 数据库快(例如),但是当你确实需要一个真正的数据库时,这似乎是一种做法。但是,是的,你真的应该尽可能多地嘲笑。我想要考虑的一件事是,您的测试拥有的代码越多,它们在测试您的实际代码时的实际可靠性就越低,而不是您编写测试以模拟您的“真实”代码的能力。 【参考方案1】:如果您正在编写单元测试,则永远不应该使用数据库。针对数据库的测试将被视为集成测试。查看 Roy Osherove 的 videos。
为了回答你的问题,(并且没有深入研究权威 RBAC,我会做这样的事情:
// assuming some RBAC class
SomeRBACClass extends RBACBaseClass
function validate(UserClass $user)
if (!$roles = $user->getRoles())
return false;
$allowed = array('admin', 'superadmin');
foreach ($roles as $role)
if (in_array($role->name, $allowed))
return true;
return false;
SomeRBACClassTest extends TestCase
function test_validate_WhenPassedUser_callsGetRolesOnUserWithNoArgs()
$rbac = new SomeRBACClass();
$user = Mockery::mock('UserClass');
$user->shouldReceive('getRoles')->once()->withNoArgs();
$rbac->validate($user);
function test_validate_getRolesOnUserReturnsCollectionOfRoles_CallsGetAttributeWithNameOnFirstRole()
$rbac = new SomeRBACClass();
$user = Mockery::mock('UserClass');
// assuming $user->getRoles() returns a collection
$collection = new \Illuminate\Support\Collection(array(
$role1 = Mockery::mock('Role'),
$role2 = Mockery::mock('Role'),
));
$user->shouldReceive('getRoles')->andReturn($collection);
$role1->shouldReceive('getAttribute')->once()->with('name');
$rbac->validate($user);
function test_validate_getAttributeWithNameOnRoleReturnsValidRole_ReturnsTrue()
$rbac = new SomeRBACClass();
$user = Mockery::mock('UserClass');
// assuming $user->getRoles() returns a collection
$collection = new \Illuminate\Support\Collection(array(
$role1 = Mockery::mock('Role'),
$role2 = Mockery::mock('Role'),
));
$user->shouldReceive('getRoles')->andReturn($collection);
$role1->shouldReceive('getAttribute')->andReturn('admin');
$result = $rbac->validate($user);
$this->assertTrue($result);
这不是我要编写的所有单元测试的完整示例,但它是一个开始。例如,我还将验证当没有返回任何角色时,结果是否为假。
【讨论】:
以上是关于如何测试依赖于具有关系的 Eloquent 模型的类?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Laravel Eloquent 中构建具有多级关系的查询
Laravel/Eloquent - 创建与可能具有或不具有属性的父模型相关的多个子模型的关系