Laravel 5 - Использование насмешек для насмешки над моделью Eloquent
Просматривал весь интернет, но, похоже, не нашел ответа на мою проблему. Я погрузился в тестирование контроллеров в Laravel с использованием PHPUnit и Mockery. Тем не менее, мне кажется, что мои модели, основанные на Eloquent, не издевались правильно. Мне удавалось издеваться над Auth::user() таким же образом, хотя это не используется в тесте ниже.
Функция в AddressController, которую нужно протестировать:
public function edit($id)
{
$user = Auth::user();
$company = Company::where('kvk', $user->kvk)->first();
$address = Address::whereId($id)->first();
if(is_null($address)) {
return abort(404);
}
return view('pages.address.update')
->with(compact('address'));
}
ControllerTest, содержащий setUp и метод mock
abstract class ControllerTest extends TestCase
{
/**
* @var \App\Http\Controllers\Controller
*/
protected $_controller;
public function setUp(){
parent::setUp();
$this->createApplication();
}
public function tearDown()
{
parent::tearDown();
Mockery::close();
}
protected function mock($class)
{
$mock = Mockery::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
}
AddressControllerTest, расширяющий ControllerTest
class AddressControllerTest extends ControllerTest
{
/**
* @var \App\Models\Address
*/
private $_address;
/**
* @var \App\Http\Controllers\AddressController
*/
protected $_controller;
public function setUp(){
parent::setUp();
$this->_controller = new AddressController();
$this->_address = factory(Address::class)->make();
}
public function testEdit404(){
$companyMock = $this->mock(Company::class);
$companyMock
->shouldReceive('where')
->with('kvk', Mockery::any())
->once();
->andReturn(factory(Company::class)->make([
'address_id' => $this->_address->id
]));
$addressMock = $this->mock(Address::class);
$addressMock
->shouldReceive('whereId')
->with($this->_address->id)
->once();
->andReturn(null);
//First try to go to route with non existing address
$this->action('GET', 'AddressController@edit', ['id' => $this->_address->id]);
$this->assertResponseStatus(404);
}
}
Ошибка, которую он продолжает выдавать:
1) AddressControllerTest::testEdit404
Mockery\Exception\InvalidCountException: Method where("kvk", object(Mockery\Matcher\Any)) from Mockery_1_Genta_Models_Company should be called exactly 1 times but called 0 times.
Возможно, у кого-нибудь есть идея?
1 ответ
Хорошо, после нахождения нескольких постов Джеффри Уэй (парень из Laracasts) рекомендует людям прекратить насмехаться над объектами Eloquent и вместо этого использовать в базах данных памяти, я попробовал этот подход. Я подумал, что это может быть очень полезно для других пользователей, имеющих такие же проблемы в будущем, поэтому я объясню ниже.
Прямо сейчас я отредактировал мой файл 'config / database.php' для поддержки опции базы данных в памяти, используя sqlite:
'sqlite' => [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
],
Далее в верхней части файла вы увидите следующую конфигурацию:
'default' => env('DB_CONNECTION', 'mysql'),
Это может остаться прежним, это означает, что Laravel проверит ваши переменные.env, чтобы найти 'DB_CONNECTION', или использует mysql по умолчанию. Это, вероятно, то, что вы хотели бы сделать, когда ваше приложение работает как обычно. Однако при тестировании вы хотели бы переопределить эту конфигурацию и временно установить конфигурацию базы данных на "sqlite". Это можно сделать, добавив переменную DB_CONNECTION в ваш файл.env:
DB_CONNECTION=mysql
Наконец, в вашем phpunit.xml, файле конфигурации, который используется Laravel для создания модульных тестов, вы должны сказать, что при тестировании эта переменная должна быть установлена в "sqlite":
<env name="DB_CONNECTION" value="sqlite"/>
Теперь все готово, и Laravel будет запускать невидимую базу данных в памяти каждый раз, когда вы собираетесь пройти тестирование. Не забудьте добавить следующую строку в тесты, которым нужна база данных.
use \Illuminate\Foundation\Testing\DatabaseMigrations;
Он скажет Laravel запустить миграцию вашей базы данных перед началом тестов, чтобы вы могли использовать таблицы, как обычно.
Таким образом, это прекрасно работает для меня! Надеюсь, вы, ребята, можете использовать это.