Я хочу использовать mock-объект (Mockery) в моем тесте PHPUnit. Объект mock должен иметь как некоторые общедоступные методы, так и некоторые общедоступные свойства. Класс – это модель 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. Что я делаю не так?
Если вы хотите получить это свойство с этим значением, просто используйте его:
$mock ->shouldReceive('getAttribute') ->with('role') ->andReturn(2);
Если вы вызываете $user->role
вы получите – 2
( $user
– его класс mock User
)
Этот ответ немного запоздал, но, надеюсь, это поможет кому-то. В настоящее время вы можете установить статическое свойство для издевающихся объектов Eloquent, используя ключевое слово 'alias':
$mocked_model = Mockery::mock('alias:Namespace\For\Model'); $mocked_model->foo = 'bar'; $this->assertEquals('bar', $mocked_model->foo);
Это также полезно для насмешек внешних классов поставщиков, таких как некоторые объекты Stripe.
Ознакомьтесь с ключевыми словами «псевдоним» и «перегрузка»: http://docs.mockery.io/en/latest/reference/startup_methods.html
Пробовал это? Он должен охватывать вас.
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));
Эта апсида дает вам возможность пообещать формат, когда вы используете getRoles (), который будет массивом объекта Role, если вы используете SOLID OOP, или если вы предпочитаете использовать массив, то, по крайней мере, вы знаете, что это всегда массив, который вы получаете.
Вы пытались делать частичные издевательства ? Вы можете попробовать что-то вроде (NOT TESTED):
$mock = Mockery::mock('User[hasRole]'); $mock->shouldReceive('hasRole')->once()->andReturn(true); $mock->roles = 2; $this->assertTrue(someTest($mock));
Чтобы ответить на ваш вопрос, вы также можете попробовать что-то вроде этого:
$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); }
Шпион – ваш друг по этому поводу:
$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));
вы можете использовать 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);