2015-04-05 8 views
10

Я пытаюсь выполнить тестирование моих контроллеров в 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, доступные мне в любом случае в моем контроллере?

+1

Я лично не думаю, что имеет смысл тестировать только контроллер.Обычно контроллер используется только для того, чтобы организовывать вещи и объединять все. Который может быть хорошо протестирован с функциональным тестированием. Если у меня есть логика, что я действительно хочу провести единичный тест (отдельно от остальных) в контроллере, это часто признак того, что его не должно быть, а скорее в службе/репозитории/модели/etc – lukasgeiter

+0

Согласовано с lukas и shift exchange ниже , Единственная ответственность диспетчера - принять запрос, делегировать задания, собрать результат и отправить его в ответ. Там не должно быть какой-либо единицы реальной работы, которую вы хотели бы протестировать, поэтому он не подлежит единичному, а функциональному тестированию. –

ответ

10

Вы не должны пытаться использовать unit test контроллеры. Они разработаны для функционального тестирования путем их вызова через протокол HTTP. Именно так спроектированы контроллеры, и Laravel предоставляет ряд утверждений в рамках структуры, которые вы можете включить в свои тесты, чтобы они работали должным образом.

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

Использование команд позволяет вам извлечь логику приложения из вашего контроллера в класс. Затем вы можете выполнить тестирование класса/команды, чтобы обеспечить ожидаемые результаты.

Затем вы можете просто вызвать команду с контроллера.

In fact the Laravel documentation tells you this:

Мы могли бы поставить все эту логику внутри метода контроллера; однако это имеет несколько недостатков ... сложнее выполнить команду-тестирование команды, так как мы также должны генерировать HTTP-запрос заглушки и сделать полный запрос к приложению для проверки логики подкаста покупки.

+0

Но как насчет модульного тестирования отдельного кода приложения? Это не отвечает на вопрос, если я собираюсь провести тестирование устройства неправильно, просто я не должен тестировать свой контроллер. Проблема в том, что мне все еще придется иметь дело с издевательством о вспомогательных функциях laravel и т. Д., Что является болью, если честно. –

+0

Да, поэтому вам следует сосредоточиться на * функциональном тестировании вашей логики приложения. Вы запускаете команды и проверяете, как получить ожидаемый результат. Я никогда не издеваюсь над своей базой данных - слишком много времени - я просто использую https://github.com/laracasts/TestDummy и базу данных SQLite для тестирования. Это очень быстро, легко писать тесты, и вам не нужно что-то издеваться ... – Laurence

Смежные вопросы