首页 文章

Mock Laravel Eloquent模型 - 如何使用Mockery设置公共 property

提问于
浏览
21

我想在PHPUnit测试中使用模拟对象(Mockery) . 模拟对象需要设置一些公共方法和一些公共属性 . 该课程是Laravel Eloquent模型 . 我试过这个:

$mock = Mockery::mock('User');
$mock->shouldReceive('hasRole')->once()->andReturn(true); //works fine
$mock->roles = 2; //how to do this? currently returns an error
$this->assertTrue(someTest($mock));

...但是设置公共属性会返回以下错误:

BadMethodCallException:方法Mockery_0_User :: setAttribute()在此模拟对象上不存在

模拟一个简单的类时不会返回此错误,但在我尝试模拟Eloquent模型时会返回此错误 . 我究竟做错了什么?

8 回答

  • 1

    如果要使用此值获取此属性,只需使用它:

    $mock ->shouldReceive('getAttribute')
        ->with('role')
        ->andReturn(2);
    

    如果你打电话 $user->role 你会得到 - 2$user - 它的 User 模拟类)

  • 2

    这个答案有点晚,但希望它会帮助某人 . 您当前可以使用'alias'关键字在模拟的Eloquent对象上设置静态属性:

    $mocked_model = Mockery::mock('alias:Namespace\For\Model');
    $mocked_model->foo = 'bar';
    $this->assertEquals('bar', $mocked_model->foo);
    

    这对于模拟外部供应商类(如某些Stripe对象)也很有帮助 .

    了解'alias'和'overload'关键字:http://docs.mockery.io/en/latest/reference/startup_methods.html

  • 12

    要回答你的问题,你也可以尝试这样的事情:

    $mock = Mockery::mock('User');
    $mock->shouldReceive('hasRole')->once()->andReturn(true); //works fine
    $mock->shouldReceive('setAttribute')->passthru();
    $mock->roles = 2; 
    
    $mock->shouldReceive('getAttribute')->passthru();
    $this->assertEquals(2, $mock->roles);
    

    或者,如seblaze所示,使用部分模拟:

    $mock = Mockery::mock('User[hasRole]');
    $mock->shouldReceive('hasRole')->once()->andReturn(true);
    $mock->roles = 2; 
    $this->assertEquals(2, $mock->roles);
    

    但是,从你的代码片段来看,如果你正在编写单元测试,那么每个测试应该只做一个断言:

    function test_someFunctionWhichCallsHasRole_CallsHasRole() {
        $mock = Mockery::mock('User');
        $mock->shouldReceive('hasRole')->once();
    
        $mock->someFunctionWhichCallsHasRole();
    }
    
    function test_someFunctionWhichCallsHasRole_hasRoleReturnsTrue_ReturnsTrue() {
        $mock = Mockery::mock('User');
        $mock->shouldReceive('hasRole')->once()->andReturn(true);
    
        $result = $mock->someFunctionWhichCallsHasRole();
    
        $this->assertTrue($result);
    }
    
  • 0

    Spy 是你的朋友:

    $mock = Mockery::spy('User');
    $mock->shouldReceive('hasRole')->once()->andReturn(true);
    $mock->roles = 2;
    $this->assertTrue(someTest($mock));
    
  • -2

    试过这个?它应该涵盖你的问题 .

    https://github.com/padraic/mockery/blob/master/docs/11-MOCKING-PUBLIC-PROPERTIES.md

    我会说实施这些

    protected $roles = array();
    
    public function setRoles($roles)
    {
        $this->roles = $roles;
    }
    
    public function addRole($role)
    {
        $this->roles[] = $role;
    }
    

    然后你可以测试使用:

    $mock = Mockery::mock('User');
    $mock->shouldReceive('hasRole')->once()->andReturn(true);
    $mock->addRole(2);
    $this->assertTrue(someTest($mock));
    

    这个apse让你有机会在你执行一个getRoles()时承诺一个格式,如果你做SOLID OOP就是Role对象的数组,或者你更喜欢使用数组,那么至少你知道它总是你得到的数组 .

  • 0

    你有没有试过partial mocks?您可以尝试类似(未测试)的内容:

    $mock = Mockery::mock('User[hasRole]');
    $mock->shouldReceive('hasRole')->once()->andReturn(true);
    $mock->roles = 2; 
    $this->assertTrue(someTest($mock));
    
  • 5

    Laravel 5.3中的部分模拟

    $mock = Mockery::mock(App\User::class)->makePartial();
    $mock->shouldReceive('hasRole')->once()->andReturn(true);
    $mock->roles = 2; 
    $this->assertEquals(2, $mock->roles);
    
  • 0

    在这种情况下你可以使用stdclass .

    $obj = new stdClass();
    $obj->roles = 2;
    $mock = Mockery::mock('User');
    // return stdclass here.
    $mock->shouldReceive('hasRole')->once()->andReturn($obj);
    $mock->roles = 2;
    $this->assertEquals(2, $mock->roles);
    

相关问题