【问题标题】:Laravel 5 'assertReponseOk' fails (gets 500 error) when I use Mockery当我使用 Mockery 时,Laravel 5 'assertReponseOk' 失败(出现 500 错误)
【发布时间】:2015-04-29 08:54:25
【问题描述】:

我正在尝试使用嘲弄来编写单元测试并且它正在工作。但是,有一件事是行不通的。

这几天我一直在寻找答案,但我没有找到任何东西,所以这就是问题所在。首先我会放一个总结版本,然后是所有代码。

这不起作用:

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' 之前没有任何效果。
  • 在 tearDown 方法中包含“parent::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');

【问题讨论】:

    标签: php unit-testing laravel-5 mockery


    【解决方案1】:

    我相信每个模拟都应该至少返回一个空数组,否则你会将 null 分配给数组。

    【讨论】:

    • 已经以各种方式(即返回不同的东西)检查了这一点。此外,在我遵循的教程/示例中,没有提到这样的事情。还是谢谢你。
    【解决方案2】:

    如果没有您的视图代码,我无法确定,但是,我很确定您的代码正在破坏,因为您的 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();
    }
    

    上面的代码没有经过测试,但你应该明白了。

    【讨论】:

    • 刚刚读过。我已经转向其他事情,但我会尝试一下。谢谢!
    猜你喜欢
    • 2016-05-24
    • 2022-08-04
    • 2023-03-09
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 2016-10-01
    • 2021-10-20
    • 1970-01-01
    相关资源
    最近更新 更多