嘲弄Laravel Eloquent模型 - 如何使用Mockery设置公共财产

时间:2014-04-07 10:00:53

标签: php laravel eloquent mockery

我想在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 个答案:

答案 0 :(得分:13)

如果您想要使用此值获取此属性,请使用它:

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

如果你致电$user->role,你会得到 - 2$user - 其User模拟类)

答案 1 :(得分:6)

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

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

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

了解'别名'并且“超载”#39;关键字: http://docs.mockery.io/en/latest/reference/startup_methods.html

答案 2 :(得分:2)

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

$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);
}        

答案 3 :(得分:1)

间谍是您的朋友:

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

答案 4 :(得分:0)

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

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对象的数组,或者你更喜欢使用数组,那么至少你知道它总是一个数组你得到。

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

Laravel 5.3中的部分模拟

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

答案 7 :(得分:-2)

在这种情况下你可以使用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);