Laravel 5 'assertReponseOk' терпит неудачу (получает ошибку 500), когда я использую Mockery

Я пытаюсь использовать насмешку для написания модульных тестов, и это работает. Однако есть одна вещь, которая не работает.

Я искал ответ несколько дней, но ничего не нашел, так что вот в чем дело. Сначала выложу краткую версию, а потом весь код.

Это не работает:

public function testIndexCallsRepository()
{
    $mock = Mockery::mock('App\Repositories\Movie\IMovieRepository');

    $mock->shouldReceive('getAll')->once();
    $mock->shouldReceive('getGenres')->once();
    $mock->shouldReceive('getCountries')->once();
    $mock->shouldReceive('getFormats')->once();
    $mock->shouldReceive('getEncodigs')->once();
    $mock->shouldReceive('getUbications')->once();

    App::instance('App\Repositories\Movie\IMovieRepository', $mock);

    $response = $this->call('GET', 'movies');

    $this->assertResponseOk();
}

При запуске phpunit последняя строка кода дает мне эту ошибку:

Expected status code 200, got 500

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

Если я удалю фиктивный код, оставив только ответ, это сработает (я получаю код состояния 200 вместо 500), поэтому я должен что-то упустить.

Я следил за некоторыми статьями о насмешках, которые включают эти две строки ответа после насмешки.

$this->call('GET', 'movies');
$this->assertResponseOk();

Так что это, кажется, очень простой материал, который работает без проблем. Одна из статей, на которую я ссылаюсь, это http://code.tutsplus.com/tutorials/testing-laravel-controllers--net-31456.

Я также пробовал:

  • написание «$this->app->instance» вместо «App::instance» и размещение его перед «shouldReceive_s» без каких-либо эффектов.
  • включая 'parent::tearDown' в методе tearDown.

Есть предположения? Что случилось?

Кстати, я в настоящее время занимаюсь обходным путем:

  • Я поставил тест с издевательством, не проверяя «assertResponseOk», и проверил, что издевательство работает, как я сказал ранее.
  • У меня есть другой способ проверить ответ, если представление получает данные и т. д., без использования моков.

Вот «полный» код, который не работает. Я не включил код репозитория. Это работает, представление отображает данные правильно.

Тестовый код:

class MovieControllerTest extends TestCase {

    public function setUp()
    {
        parent::setUp();
    }

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

    public function testIndexCallsRepository()
    {
        $mock = Mockery::mock('App\Repositories\Movie\IMovieRepository');

        $mock->shouldReceive('getAll')->once();
        $mock->shouldReceive('getGenres')->once();
        $mock->shouldReceive('getCountries')->once();
        $mock->shouldReceive('getFormats')->once();
        $mock->shouldReceive('getEncodigs')->once();
        $mock->shouldReceive('getUbications')->once();

        App::instance('App\Repositories\Movie\IMovieRepository', $mock);

        $response = $this->call('GET', 'movies');

        $this->assertResponseOk();
    }

    public function testIndexResponseIsOkAndViewHasAllTheData()
    {
        $response = $this->call('GET', 'movies');

        $this->assertResponseOk();

        $this->assertViewHas('movies');
        $this->assertViewHas('genre_options');
        $this->assertViewHas('country_options');
        $this->assertViewHas('format_options');
        $this->assertViewHas('encoding_options');
        $this->assertViewHas('ubication_options');

        $movies     = $response->original->getData()['movies'];
        $genres     = $response->original->getData()['genre_options'];
        $countries  = $response->original->getData()['country_options'];
        $formats    = $response->original->getData()['format_options'];
        $encodings  = $response->original->getData()['encoding_options'];
        $ubications = $response->original->getData()['ubication_options'];

        $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', 
            $movies);
        $this->assertInternalType('array', $genres);
        $this->assertInternalType('array', $countries);
        $this->assertInternalType('array', $formats);
        $this->assertInternalType('array', $encodings);
        $this->assertInternalType('array', $ubications); 
    }
}

Код контроллера:

<?php namespace App\Http\Controllers;

use App\Repositories\Movie\IMovieRepository;

class MovieController extends Controller {

    protected $movie;

    public function __construct(IMovieRepository $movie)
    {
        $this->movie = $movie;
    }

    public function index()
    {
        $data['movies']            = $this->movie->getAll();
        $data['genre_options']     = $this->movie->getGenres();
        $data['country_options']   = $this->movie->getCountries();
        $data['format_options']    = $this->movie->getFormats();
        $data['encoding_options']  = $this->movie->getEncodings();
        $data['ubication_options'] = $this->movie->getUbications();

        return view('movies.index', $data);
    }
}

Маршрут:

Route::get('movies', 'MovieController@index');

person acl450    schedule 26.02.2015    source источник


Ответы (2)


Я считаю, что каждое издевательство должно возвращать как минимум пустой массив, потому что в противном случае вы присваиваете массиву значение null.

person Mauro Moreno    schedule 28.02.2015
comment
Проверяли это разными способами (то есть возвращая разные вещи). Кроме того, в учебниках/примерах, которым я следовал, нет упоминания об этом. Все равно спасибо. - person acl450; 02.03.2015

Без вашего кода представления я не могу быть уверен, но я почти уверен, что ваш код ломается, потому что ваше представление movies.index требует, чтобы определенные ключи массива $data не могли быть нулевыми. Я бы предложил одно из следующего:

Обход логики просмотра

public function testIndexCallsRepository()
{
    $mock = Mockery::mock('App\Repositories\Movie\IMovieRepository');

    $mock->shouldReceive('getAll')->once()->andReturn('all');
    $mock->shouldReceive('getGenres')->once()->andReturn('genres');
    $mock->shouldReceive('getCountries')->once()->andReturn('countries');
    $mock->shouldReceive('getFormats')->once()->andReturn('formats');
    $mock->shouldReceive('getEncodigs')->once()->andReturn('encodings');
    $mock->shouldReceive('getUbications')->once()->andReturn('ubications');

    App::instance('App\Repositories\Movie\IMovieRepository', $mock);

    $expectedViewData = array(
         'movies' => 'movies',
         'genre_options' => 'genres',
         'country_options' => 'countries',
         'format_options' => 'formats',
         'encoding_options' => 'encodings',
         'ubication_options' => 'ubications',
    );

    View::shouldReceive('make')->once()->with('movies.index', $expectedViewData)->andReturn('compiled view'); 

    $response = $this->call('GET', 'movies');

    $this->assertResponseOk();
}

Имитация ответов из репозитория

public function testIndexCallsRepository()
{
    $mock = Mockery::mock('App\Repositories\Movie\IMovieRepository');

    $mock->shouldReceive('getAll')->once()->andReturn(array('all'));
    $mock->shouldReceive('getGenres')->once()->andReturn(array('genres'));
    $mock->shouldReceive('getCountries')->once()->andReturn(array('countries'));
    $mock->shouldReceive('getFormats')->once()->andReturn(array('formats'));
    $mock->shouldReceive('getEncodigs')->once()->andReturn(array('encodings'));
    $mock->shouldReceive('getUbications')->once()->andReturn(array('ubications'));

    App::instance('App\Repositories\Movie\IMovieRepository', $mock);

    $response = $this->call('GET', 'movies');

    $this->assertResponseOk();
}

Приведенный выше код не тестировался, но вы должны получить представление.

person awei    schedule 15.04.2015
comment
Только что прочитал. Я перешел на другие вещи, но я попробую. Благодарю вас! - person acl450; 08.11.2015