Laravel 4 phpunit 测试:测试标记为“风险”,因为没有关闭自己的输出缓冲区

Posted

技术标签:

【中文标题】Laravel 4 phpunit 测试:测试标记为“风险”,因为没有关闭自己的输出缓冲区【英文标题】:Laravel 4 phpunit test: Test flagged as `risky` for not closing its own output buffers 【发布时间】:2014-08-15 20:12:55 【问题描述】:

我在尝试在 phpunit 测试中测试简单的 Illuminate\Http\Response 对象时遇到问题。有问题的错误是:

PHPUnit 4.3-dev by Sebastian Bergmann.

Configuration read from /var/MyApp/phpunit.xml

....................R.................

Time: 2.71 seconds, Memory: 76.75Mb

OK, but incomplete, skipped, or risky tests!
Tests: 38, Assertions: 55, Risky: 1.     

phpunit --tap as 运行时显示 R 的位置

# RISKY Test code or tested code did not (only) close its own output buffers

我要测试的类是:

class PrettyError 

    /**
     * Renders a pretty 500 error page view
     *
     * @return string with error view
     */
    public function render()
    
             return Response::make(View::make('viewName')->with('param','value')->render(), 500, array());
    

测试是

class Pretty500Test extends BaseTest 

    /** @var Pretty500 */
    private $pretty500;

    /**
     * Set dependencies
     */
    public function __construct()
    
        $this->pretty500 = app(PrettyError::class);
    

    public function testRender()
    
        $response = $this->pretty500->render();

        //assertions below, never get reached cause tests aborts after above call
        $this->assertsTrue('500',$response->getStatus());
    

    

请注意,使用 laravel 在我的应用程序中测试任何路线时都会发生相同的错误

this->route('GET','routeName')

helper 方法,所以这似乎是与响应请求相关的一般错误。据我所知,我的应用程序中没有任何东西在输出缓冲(有目的地)做任何时髦的事情,这是我能想到的唯一可能会破坏 Response 类的标准工作的事情。

我正在使用 phpunit 4.3-dev、laravel 4.2.1 和 mocky 进行测试。

就这个特别危险的错误代码而言,我在互联网上根本没有找到太多信息,所以如果没有进一步的帮助,我会不知所措。

【问题讨论】:

在全新安装的 Laravel 上尝试一下 - 你仍然遇到问题吗? 不,我还没有尝试过全新安装,接下来我会这样做,以确保它不在我正在使用的 TestCase 设置中 更新:我将问题隔离了一点,它与 Request 类本身无关,而是与内部 View 调用有关,所以基本上View::make('viewName')->with('param','value')->render() 触发了 phpunit 风险警告,没有任何其他内容测试。由于我的应用程序中的 View 实例不是本机 laravel 实例,而是使用自定义实例进行热交换,但建立在此之上(它注册了一些有用的 View 作曲家),也许其中有一些测试不喜欢的东西 实际上 - 我刚刚注意到您正在“制作”一个视图,渲染它,然后将其发送到 Response 类以重新渲染? 是的,基本上我正在创建一个带有自定义标题和状态代码的响应,它的内容只是呈现的视图。我现在看了一下文档,有一个速记方法Response::view('hello')->header('Content-Type', $type); 可以立即使用它,但除此之外它是正确的 AFAIK 【参考方案1】:

原来问题是由于使用了有问题的视图

Input::old()

在表单中。在尝试在任何 phpunit 测试中简单地访问 Input::old('foo') 后,我得到了一个

RuntimeException: Session store not set on request.

所以真正的罪魁祸首是在我的单元测试中的会话存储中,而不是任何请求/视图渲染问题。通过在 testRender() 方法中为当前 Request 实例设置会话存储解决了问题:

\Illuminate\Support\Facades\Request::setSession($this->app['session.store'])

【讨论】:

【参考方案2】:

我遇到了非常相似的问题。问题是我试图在视图中获取非对象(NULL)的属性,而不是 PHP 错误“试图获取非对象的属性”phpunit 显示“好的,但不完整、跳过或有风险的测试!” .

因此,如果您遇到同样的问题,请检查视图文件中的此类错误。

【讨论】:

【参考方案3】:

也发生在 Laravel 5 中。 当响应格式不正确时,PHPUnit 会抛出这个。

这可能是由于:

Laravel 应用中的错误:检查日志 不正确的 Blade 语法:例如在我的例子中,有一个过多的 Blade @stop 被 Laravel 不认为是错误(并且没有被记录)

【讨论】:

与我的安装相同。没有 @endsection 来关闭我的模板文件中打开的部分。 也只是想插话。我在为 Laravel 5.1app 编写测试时遇到了这个令人发狂的风险问题。这条评论让我走上了正确的道路,事实证明我在 Blade 模板中有一个过时的 @show 语句,这导致了问题。如果您想在您的 Laravel 应用程序(或与此相关的任何应用程序)中查找至少包含一个 @endsection 语句的所有文件,请运行以下命令: grep -cr "@endsection" 。 | sed '/:0$/d' | sort -k2n -t:这很有用,因为 grep 的默认行为是列出 所有 个文件和出现次数。【参考方案4】:

我有来自 PhpUnit 的相同错误消息,喜欢你的。我在视图(刀片)文件的错误行上写了 '@stop'。我通过将右 '@stop' 移动到右行进行了编辑,而不是 PHPUnit 测试通过了!

尝试检查刀片文件中的 @section @stop 块。

【讨论】:

【参考方案5】:

封闭式三元运算符 (?) 不够好

在 Laravel 5 中进行测试时,我遇到了同样的风险测试用例问题。这里的问题是,我的导航(默认布局文件)中有如下代码:

<li Request::is('clients*')?' class="active"':'' ><a href="/clients">Clients</a></li>

测试不喜欢这部分,因为三元运算符(?)关闭得不够好。我将其替换为以下内容以使其正常工作(在三元运算符部分周围添加了括号):

<li (Request::is('clients*')?' class="active"':'') ><a href="/clients">Clients</a></li>

我通过从请求的视图、它扩展的布局和包含的文件中逐部分删除刀片语法找到了这一点。在删除上面的语法时它起作用了,所以出现了错误。

空产量/节

当我为收益传递一个空值时,发生了同样的错误,例如在以下场景中:

layout.blade.php

<h1>@yield('title')</h1>

page.blade.php

@extends('layout')    
@section('title','') //<-- This empty value raised the error

其他需要考虑的事项

也许很清楚,但以防万一您犯了同样的错误:您必须检查所有涉及的文件。

我运行了以下测试,访问登录页面,输入电子邮件和密码并按下登录按钮:

测试/AuthenticationTest.php

<?php
class AuthenticationTest extends TestCase

    // [...]

    public function testLoginSuccessful()
    
        $password = str_random();

        $user = factory(App\User::class)->create(['password' => $password]);

        $this->visit(route('login'))
            ->type($user->email, 'email')
            ->type($password, 'password')
            ->press('Login')
            ->seePageIs(route('dashboard2'));
    

app/Http/routes.php

<?php
Route::get('auth/login',    'Auth\AuthController@getLogin')->name('login');
Route::post('auth/login',   'Auth\AuthController@postLogin');

app/Http/Controllers/Auth/AuthController.php

<?php    
// [...]
class AuthController extends Controller

    // [...]

    protected $redirectPath = '/dashboard2'; // <-- check this file as well

所以我必须特别检查以下我进行修改的文件:

app/Http/routes.php app/Http/Controllers/Auth/AuthController.php -> 函数getLogin resources/views/auth/login.blade.php(在 Auth\AuthContoller@getLogin 中返回) app/Http/Controllers/Auth/AuthController.php -> 函数postLogin resources/views/dashboard2.blade.php(登录成功后返回)

【讨论】:

空白部分也引起了我的注意。将其更改为 @section('name', null) 使其没有风险,但现在看起来像代码异味:-/ @section('title','') 引起了问题。谢谢! 对我来说,我必须将 @section('title') 包装在 @hasSection 块中 - 使用 null 而不是 '' 并没有成功。【参考方案6】:

重复的@section('content') 行有同样的问题

@section('content')

@section('content')
...
@endsection

错字!!

【讨论】:

以上是关于Laravel 4 phpunit 测试:测试标记为“风险”,因为没有关闭自己的输出缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

在 laravel 4 中使用 phpunit 测试 POST

使用 PHPUnit 对 Laravel 4 进行单元测试

Laravel 4 PHPUnit Sqlite 数据库,每次测试前删除项目

如何使用 phpunit 在 Laravel 4 中测试命名空间对象

使用 phpunit DB::table()->get() 测试 Laravel 4.2 返回数组而不是对象

Laravel 5.4 上的示例 PHPUnit 测试失败并显示 404