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

时间:2022-10-15 23:06:54

I want to use a mock object (Mockery) in my PHPUnit test. The mock object needs to have both some public methods and some public properties set. The class is a Laravel Eloquent model. I tried this:

我想在我的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));

... but setting the public property returns this error:

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

BadMethodCallException: Method Mockery_0_User::setAttribute() does not exist on this mock object

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

This error is not returned when mocking a simple class, but is returned when I try to mock an Eloquent model. What am I doing wrong?

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

7 个解决方案

#1


11  

If you want getting this property with this value, just use it:

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

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

If you call $user->role you will get - 2 ($user - its User mock class)

如果你调用$ user-> role你会得到 - 2($ user - 它的User mock类)

#2


4  

This answer is a bit late but hopefully it will help someone. You can currently set a static property on mocked Eloquent objects by using the 'alias' keyword:

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

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

This is also helpful for mocking external vendor classes like some of the Stripe objects.

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

Read about 'alias' and 'overload' keywords: http://docs.mockery.io/en/latest/reference/startup_methods.html

阅读'别名'和'重载'关键字:http://docs.mockery.io/en/latest/reference/startup_methods.html

#3


1  

To answer your question, you could also try something like this:

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

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

Or, as suggested by seblaze, use a partial mock:

或者,如seblaze所建议的那样,使用部分模拟:

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

But, from your code snippet, if you're writing unit tests, you should really only make one assertion per each test:

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

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

#4


0  

Tried this? It should cover you issue.

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

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

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

I'd say implement these

我会说实施这些

protected $roles = array();

public function setRoles($roles)
{
    $this->roles = $roles;
}

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

Then you can test using:

然后你可以测试使用:

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

This apse gives you the opportunity to promise a format when you do a getRoles() which would be array of Role object if you do SOLID OOP, or if you rather use array, then at least you know it's always an array you get.

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

#5


0  

Did you tried to do partial mocks ? You can try something like ( NOT TESTED ) :

你试过做部分嘲笑吗?您可以尝试类似(未测试):

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

#6


0  

Spy is your friend on this:

间谍是你的朋友:

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

#7


-2  

you can use stdclass in this case.

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

#1


11  

If you want getting this property with this value, just use it:

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

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

If you call $user->role you will get - 2 ($user - its User mock class)

如果你调用$ user-> role你会得到 - 2($ user - 它的User mock类)

#2


4  

This answer is a bit late but hopefully it will help someone. You can currently set a static property on mocked Eloquent objects by using the 'alias' keyword:

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

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

This is also helpful for mocking external vendor classes like some of the Stripe objects.

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

Read about 'alias' and 'overload' keywords: http://docs.mockery.io/en/latest/reference/startup_methods.html

阅读'别名'和'重载'关键字:http://docs.mockery.io/en/latest/reference/startup_methods.html

#3


1  

To answer your question, you could also try something like this:

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

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

Or, as suggested by seblaze, use a partial mock:

或者,如seblaze所建议的那样,使用部分模拟:

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

But, from your code snippet, if you're writing unit tests, you should really only make one assertion per each test:

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

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

#4


0  

Tried this? It should cover you issue.

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

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

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

I'd say implement these

我会说实施这些

protected $roles = array();

public function setRoles($roles)
{
    $this->roles = $roles;
}

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

Then you can test using:

然后你可以测试使用:

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

This apse gives you the opportunity to promise a format when you do a getRoles() which would be array of Role object if you do SOLID OOP, or if you rather use array, then at least you know it's always an array you get.

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

#5


0  

Did you tried to do partial mocks ? You can try something like ( NOT TESTED ) :

你试过做部分嘲笑吗?您可以尝试类似(未测试):

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

#6


0  

Spy is your friend on this:

间谍是你的朋友:

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

#7


-2  

you can use stdclass in this case.

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