Издевательство над Laravel
Я пытаюсь настроить самые простые тесты в моем контроллере, но, как и в большинстве случаев с Laravel, не существует достойных руководств для демонстрации простых вещей.
Я могу запустить простой тест (в файле с именем UserControllerTest), например:
public function testIndex()
{
$this->call('GET', 'users');
$this->assertViewHas('users');
}
Это вызывает маршрут /users и передает массив users.
Я хочу сделать то же самое с издевательством, но как?
Если я попробую это:
public function testIndex()
{
$this->mock->shouldReceive('users')->once();
$this->call('GET', 'users');
}
Я получаю сообщение об ошибке, что "Статический метод Mockery_0_users::all не существует в этом фиктивном объекте.
Почему бы и нет? Я издеваюсь над пользователем, который расширяет Ardent и, в свою очередь, расширяет Eloquent. Почему:: все не существует для макета?
Кстати, это функции настройки для Mockery:
public function setUp()
{
parent::setUp();
$this->mock = $this->mock('User');
}
public function mock($class)
{
$mock = Mockery::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
2 ответа
Вы не можете напрямую издеваться над классом Eloquent. Eloquent не является ни Фасадом, ни вашей моделью пользователя. В Laravel есть немного магии, но вы не можете делать такие вещи.
Если вы хотите смоделировать свой класс User, вы должны внедрить его в конструктор контроллера. Шаблон репозитория является хорошим подходом, если вы хотите это сделать. Есть много статей об этом шаблоне и Laravel в Google.
Вот несколько фрагментов кода, чтобы показать вам, как это может выглядеть:
class UserController extends BaseController {
public function __construct(UserRepositoryInterface $users)
{
$this->users = $users;
}
public function index()
{
$users = $this->users->all();
return View::make('user.index', compact('users'));
}
}
class UserControllerTest extends TestCase
{
public function testIndex()
{
$repository = m::mock('UserRepositoryInterface');
$repository->shouldReceive('all')->andReturn(new Collection(array(new User, new User)));
App::instance('UserRepositoryInterface', $repository);
$this->call('GET', 'users');
}
}
Если вам кажется, что для вашего проекта слишком много структурирования, вы можете просто вызвать реальную базу данных в своих тестах и не издеваться над классами моделей... В классическом проекте это просто отлично работает.
Эта функция является частью проекта под названием apiato.io
Вы можете использовать его для макетирования любого класса в Laravel, даже фасадного, в основном всего, что может быть разрешено с помощью IoC, а это почти все классы, если вы используете правильное внедрение зависимостей:
/**
* Mocking helper
*
* @param $class
*
* @return \Mockery\MockInterface
*/
public function mock($class)
{
$mock = Mockery::mock($class);
App::instance($class, $mock);
return $mock;
}