【问题标题】:How to test a class which depends on an Eloquent model with relationships?如何测试依赖于具有关系的 Eloquent 模型的类?
【发布时间】:2014-05-19 13:36:46
【问题描述】:

为依赖于具有关系的 Eloquent 模型的类编写单元测试的最佳方法是什么?例如

  • 真实对象(带数据库)。这很容易,但速度很慢。

  • 真实对象(无数据库)。我可以创建一个新对象,但我看不到如何在不写入数据库的情况下设置相关模型。

  • 模拟对象。我在使用 Mockery 和 Eloquent 模型时遇到了问题(例如,请参阅 this question)。

  • 其他解决方案?

context:我使用 Laravel 和 Authority RBAC 进行访问控制。我想找到在单元测试中测试我的访问规则的最佳方法。这意味着我需要在测试期间将用户依赖项传递给授权。

【问题讨论】:

  • 权宜之计是使用内存中的 SQLite 数据库进行测试。我认为默认情况下 Laravel 实际上会为您执行此操作,尽管您确实需要在设置时调用播种机。不知道它是否真的比 MySQL 数据库快(例如),但是当你确实需要一个真正的数据库时,这似乎是一种做法。但是,是的,你真的应该尽可能多地嘲笑。我想要考虑的一件事是,您的测试拥有的代码越多,它们在测试您的实际代码时的实际可靠性就越低,而不是您编写测试以模拟您的“真实”代码的能力。

标签: php unit-testing laravel eloquent mockery


【解决方案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);
    }

这不是我要编写的所有单元测试的完整示例,但它是一个开始。例如,我还将验证当没有返回任何角色时,结果是否为假。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 2017-05-21
    • 2019-10-13
    • 2020-05-15
    • 1970-01-01
    相关资源
    最近更新 更多