Подтвердить что ты не робот

Издевательские модели Laravel Eloquent - как установить публичную собственность с помощью Mockery

Я хочу использовать 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. Что я делаю неправильно?

4b9b3361

Ответ 1

Если вы хотите получить это свойство с этим значением, просто используйте его:

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

Если вы позвоните $user->role, вы получите - 2 ($user - его User фиктивный класс)

Ответ 2

Этот ответ немного запоздал, но, надеюсь, он кому-нибудь поможет. В настоящее время вы можете установить статическое свойство для ложных объектов Eloquent с помощью ключевого слова alias:

$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

Ответ 3

Чтобы ответить на ваш вопрос, вы также можете попробовать что-то вроде этого:

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

Ответ 4

Шпион ваш друг на этом:

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

Ответ 5

Пробовал это? Он должен охватывать вас.

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, или если вы предпочитаете использовать массив, то, по крайней мере, вы знаете, что это всегда массив, который вы получить.

Ответ 6

Вы пытались сделать частичные mocks? Вы можете попробовать что-то вроде (NOT TESTED):

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

Ответ 7

Частичный макет в Laravel 5.3

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

Ответ 8

вы можете использовать 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);