Насмешка ложноположительна в тесте контроллера Laravel

Я пытаюсь научиться использовать Mockery с Laravel 5. Я основывал свои усилия в основном на книге Уэя (Laravel Testing Decoded) и других учебниках, в которых говорится, что для интеграции [с PHPUnit] требуется только метод tearDown(). Так что я включил это. Проблема в том, что он, кажется, не сбрасывает вещи между тестами. Содержимое моего тестового класса выглядит примерно так:

public function __construct()
{
    $this->mock = Mockery::mock('Class\To\Mock');
}

public function tearDown()
{
    Mockery::close();
}

public function test_RedirectWithoutAuthentication()
{
    // Act
    $this->call('GET', '/path/1');

    // Assert
    $this->assertRedirectedTo('/auth/login');
}

public function test_X()
{
    // Arrange
    $this->mock->shouldReceive('MockedClassMethod')->once();

    // Act
    $this->call('GET', '/path/1');
}

Первый тест работает, и промежуточное ПО Auth отправляет пользователя на страницу входа. В интересах TDD я написал второй тест до того, как MockedClassMethod был фактически написан. Так что, на мой взгляд, он должен эффектно потерпеть неудачу. Но это не так. Это проходит!

Если я изменю порядок тестов, он «работает» (незаписанный терпит неудачу, аутентификация проходит), что заставляет меня поверить, что на самом деле это не проблема порядка, а что-то связанное с тем, что один тест не очищается перед следующим.

Любая информация спасет мои оставшиеся волосы от вырывания. :-)


person LavaWings    schedule 03.08.2015    source источник
comment
Вы пытались поместить определение mocky mock в метод установки вместо конструктора?   -  person Matteo    schedule 04.08.2015
comment
Можете попробовать заменить public function __construct() на protected function setUp()?   -  person Matteo    schedule 04.08.2015


Ответы (2)


В соответствии с документом по PHPUnit:

Шаблонные методы setUp() и tearDown() запускаются один раз для каждого тестового метода (и для новых экземпляров) класса тестового примера.

Конструктор вызывается только в первый раз, поэтому tearDown вызывается перед вторым выполнением теста класса, и эффект заключается в том, что насмешливый экземпляр был закрыт.

Чтобы решить вашу проблему, вы можете использовать метод установки для инициализации издевательского объекта. Поэтому замените конструктор класса тестового класса на метод установки следующим образом:

Попробуйте использовать это:

protected function setUp() 
{
    $this->mock = Mockery::mock('Class\To\Mock');
}

вместо:

public function __construct()
{
    $this->mock = Mockery::mock('Class\To\Mock');
}

Надеюсь, это поможет

person Matteo    schedule 04.08.2015

Я пытался использовать метод setUp(), описанный Маттео, и это привело к тому, что тесты вообще не запускались. Поэтому я отказался от этого курса, думая, что я далеко. Но предложение Маттео вернуло меня к нему.

Небольшое изучение того, почему это привело к сбою тестов, показало, что объект $app так и не был создан. Хм... И тут до меня дошло, что метод setUp() переопределяет некоторые важные вещи. Поэтому, чтобы исправить это, все, что нужно было, это сначала вызвать родительский метод! Вот так:

public function setUp()
{
    parent::setUp();
    $this->mock = Mockery::mock('Class\To\Mock');
}

С этого момента setUp() и tearDown() работали как положено.

Я до сих пор не уверен, почему все примеры, которые я нашел, показывают, что макет создается в конструкторе. Может быть, я все еще чего-то не понимаю, но, по крайней мере, это работает... пока. :-)

person LavaWings    schedule 04.08.2015
comment
Привет, Джаред, конечно! Я не знал, что в вашем тестовом классе есть иерархия с уже реализованным методом setup. Рад, что работает нормально! Удачи! - person Matteo; 04.08.2015
comment
Бесконечно благодарен. Мне потребовались бы годы, чтобы вернуться к setUp() без вашего предложения. Одна из тех вещей, на которые вы тратите весь день, и она прямо перед вами... - person LavaWings; 04.08.2015
comment
привет @jared Добро пожаловать! пожалуйста, проголосуйте за мой ответ, если вы считаете его полезным - person Matteo; 04.08.2015