Я пытаюсь выполнить тестирование моих контроллеров в Laravel 5, но у меня серьезные проблемы, обворачивающие его вокруг. Похоже, мне приходится торговать большими функциями коротких рук и статическими классами для эквивалентных инъекций эквивалентов, если я действительно хочу провести изолированное модульное тестирование.Laravel 5 тестирование изолированных контроллеров
Прежде всего, то, что я вижу в documentation как «модульное тестирование», не является модульным тестированием для меня. Это похоже на функциональное тестирование. Я не могу протестировать изолированную функцию контроллера, так как мне придется пройти через всю инфраструктуру и мне нужно будет засеять мою базу данных, если у меня есть код, взаимодействующий с моей базой данных.
Итак, в свою очередь, я хочу проверить свои контроллеры, изолированные от рамки. Это, однако, довольно сложно.
Давайте посмотрим на пример функции (я сохранил некоторые части этой функции для вопроса):
public function postLogin(\Illuminate\Http\Request $request)
{
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->has('remember')))
{
return redirect()->intended($this->redirectPath());
}
}
Теперь проблема возникает в последних строках. Конечно, я могу высмеять экземпляр Request, который отправлен в функцию, это не проблема. Но как я буду высмеивать класс Auth или функцию перенаправления? Мне нужно переписать мой класс/функции с инъекцией зависимостей, как это:
private $auth;
private $redirector;
public function __construct(Guard $auth, \Illuminate\Routing\Redirector $redirector)
{
$this->auth = $auth;
$this->redirector = $redirector;
}
public function postLogin(\Illuminate\Http\Request $request)
{
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if ($this->auth->attempt($credentials, $request->has('remember')))
{
return $this->redirector->intended($this->redirectPath());
}
}
И я в конечном итоге с модульного тестирования извилистый, полный издевается:
public function testPostLoginWithCorrectCredentials()
{
$guardMock = \Mockery::mock('\Illuminate\Contracts\Auth\Guard', function($mock){
$mock->shouldReceive('attempt')->with(['email' => 'test', 'password' => 'test'], false)->andReturn(true);
});
$redirectorMock = \Mockery::mock('\Illuminate\Routing\Redirector', function($mock){
$mock->shouldReceive('intended')->andReturn('/somePath');
});
$requestMock = \Mockery::mock('\Illuminate\Http\Request', function($mock){
$mock->shouldReceive('only')->with('email', 'password')->andReturn(['email' => 'test', 'password' => 'test']);
$mock->shouldReceive('has')->with('remember')->andReturn(false);
});
$object = new AuthController($guardMock, $redirectorMock);
$this->assertEquals('/somePath', $object->postLogin($requestMock));
}
Теперь, если я что-нибудь более сложным логику, которая, например, использовала бы модель, я должен был бы и так зависеть от этого, и издеваться над ней в моем классе.
Мне кажется, что Laravel не предоставляет то, что я хочу, или моя логика тестирования ошибочна. Есть ли способ проверить мои функции контроллера, не выходя из контрольных функций тестирования, и/или иметь возможность вводить стандартные классы Laravel, доступные мне в любом случае в моем контроллере?
Я лично не думаю, что имеет смысл тестировать только контроллер.Обычно контроллер используется только для того, чтобы организовывать вещи и объединять все. Который может быть хорошо протестирован с функциональным тестированием. Если у меня есть логика, что я действительно хочу провести единичный тест (отдельно от остальных) в контроллере, это часто признак того, что его не должно быть, а скорее в службе/репозитории/модели/etc – lukasgeiter
Согласовано с lukas и shift exchange ниже , Единственная ответственность диспетчера - принять запрос, делегировать задания, собрать результат и отправить его в ответ. Там не должно быть какой-либо единицы реальной работы, которую вы хотели бы протестировать, поэтому он не подлежит единичному, а функциональному тестированию. –