Я запускаю phpunit с насмешкой (без БД/фикстур), но у меня проблемы с насмешкой над моделью.

$customer = Mockery::mock(CustomerModel::class);
echo $customer->id;

Выдает ошибку:

BadMethodCallException: Method Mockery_1_models_Customer::hasAttribute() does not exist on this mock object

Потом попробовал:

$customer->shouldReceive('hasAttribute')->andReturn(true);

Но снова я натыкаюсь на:

Fatal error: Call to a member function getDb() on a non-object in ..\yiisoft\yii2\db\ActiveRecord.php on line 135

Какие-либо предложения?

8
Mārtiņš Briedis 3 Июл 2015 в 14:28

2 ответа

Я знаю, что вы не принимаете ответы на приспособления, но я тоже не мог этого понять. Проблема, которую я пытался решить, на самом деле заключалась в том, чтобы имитировать некоторые методы в модели, чтобы избежать создания базовых фикстур.

В итоге я использовал реализацию шаблона Proxy в Mockery.

private $_product;
public function testMe() 
{
   // Here we use fixtured instance of Product model to build a Proxy
   $this->_product = \Mockery::mock($this->product('product1')); 
   // somehow model attributes are inaccessible via proxy, but we can set them directly as a Proxy property
   $this->_product->id = 1; 
   $this->_product->shouldReceive('getPrice')->andReturn(1000);
   // assertions below
   ...
}

В этом примере метод getPrice() из модели Product возвращает цену Product из связанных таблиц. И мы издеваемся над этим здесь, чтобы нам не пришлось заполнять БД всеми связанными моделями фикстур. Тем не менее Product сам по себе по-прежнему является приспособлением.

Возможно, это не лучшее решение, но мне удалось сэкономить немного процессорного времени, сохраняя развязку модульных тестов.

Документы здесь http://docs.mockery.io/en/latest/reference/partial_mocks.html

обновить :

Я также сделал небольшой помощник для решения проблемы с проксированием атрибутов.

/**
 * @param \yii\base\Model $model
 * @return \Mockery\MockInterface
 */
private function setupMock($model)
{
    $mock = \Mockery::mock($model);
    foreach ($model->getAttributes() as $key => $value) {
        $mock->$key = $value;
    }
    return $mock;
}

Таким образом, все атрибуты и соответствующие им значения из исходной модели становятся доступны в макете.

4
paulus 15 Июл 2015 в 00:11
Спасибо, попробую!
 – 
Mārtiņš Briedis
13 Июл 2015 в 09:55

Является ли традиционным частичным макетом или Пассивный частичный макет что вы ищете?

$customer = Mockery::mock(CustomerModel::className())->makePartial();
echo $customer->id;

Приведенный выше пример, конечно, ничего не вернет, поскольку id не установлен, но не выдаст никаких ошибок.

1
Rutger 13 Июл 2015 в 14:56
Я думаю, что это проблема в первую очередь. Этот подход создает новый экземпляр CustomerModel, который не является постоянным с точки зрения ActiveRecord. В то же время вы не можете имитировать идентификатор, потому что $customer->id = 123 почему-то не будет присваивать значение
 – 
paulus
13 Июл 2015 в 17:37