php - Controller 的 Laravel 单元测试

标签 php unit-testing laravel-4 phpunit

我正在尝试按照 TDD 启动一个新的 Laravel 应用

我的第一步是检查是否在主页 url 上调用了/login Controller 。

尽管遵循了几个教程,但我无法让测试正常工作,而且我根本看不出我做错了什么。

我的设置是: Composer 安装laravel composer 安装 phpunit

这是我的路线:

<?php
Route::get('/login', 'AuthenticationController@login');

我的 Controller :

<?php

class AuthenticationController extends BaseController {

    public function login () {
        return View::make('authentication.login');
    }

}

还有我的测试:

<?php

class AuthenticationTest extends TestCase {

    public function testSomeTest () {

        $response = $this->action('GET', 'AuthenticationController@login');

        $view = $response->original;

        $this->assertEquals('authentication.login', $view['name']);
    }
}

我得到的错误是

  ErrorException: Undefined index: name

代码是 Laravel 站点的副本(几乎完全相同),但它无法运行。

谁能看出我做错了什么?

它声称 $view 没有索引名称,但这不可能像 laravel 网站上的示例那样正确,而且 View 是使用它的名称呈现的(它也在前端正确显示)

编辑::

所以从评论看来,laravel 单元测试部分并不清楚,$view['name'] 正在检查名为 $name 的变量。如果是这样,您如何测试使用的 Controller /路由,IE。什么 Controller 名称/ Action 名称已用于路由('X')

最佳答案

更新,2020-07-01:

由于这个答案似乎仍然不时得到一些赞成票,我只是想指出,我认为这不再是一个好的测试方法。自 v4 以来,Laravel 极大地改进了测试体验,并且整体范式发生了相当显着的转变,从单元和类转向功能和端点。这不仅是惯用的更改,而且从技术角度来看似乎更有意义。

此外,从那时起,还引入了许多新的和有用的测试助手,它们允许进行不那么脆弱的测试。请参阅文档以获取概述和基本测试示例。


好的,正如评论中已经解释的那样,让我们​​先退后一步,考虑一下这个场景。

"My first step is to check that the /login controller is called on the home url."

所以这意味着:当用户访问 home 路由时,您想要检查用户是否已登录。如果他没有登录,您想要将他们重定向到登录页面,可能带有一些闪现消息。在他们登录后,您希望将他们重定向回主页。如果登录失败,您希望将他们重定向回登录表单,也许还带有一条闪现消息。

所以现在有几个东西要测试:家庭 Controller 和登录 Controller 。因此,遵循 TDD 精神,让我们首先创建测试。

注意:我将遵循 phpspec 使用的一些命名约定,但不要因此而烦恼。

class HomeControllerTest extends TestCase
{
    /**
     * @test
     */
    public function it_redirects_to_login_if_user_is_not_authenticated()
    {
        Auth::shouldReceive('check')->once()->andReturn(false);

        $response = $this->call('GET', 'home');
        
        // Now we have several ways to go about this, choose the
        // one you're most comfortable with.

        // Check that you're redirecting to a specific controller action 
        // with a flash message
        $this->assertRedirectedToAction(
             'AuthenticationController@login', 
             null, 
             ['flash_message']
        );
        
        // Only check that you're redirecting to a specific URI
        $this->assertRedirectedTo('login');

        // Just check that you don't get a 200 OK response.
        $this->assertFalse($response->isOk());

        // Make sure you've been redirected.
        $this->assertTrue($response->isRedirection());
    }

    /**
     * @test
     */
    public function it_returns_home_page_if_user_is_authenticated()
    {
        Auth::shouldReceive('check')->once()->andReturn(true);

        $this->call('GET', 'home');

        $this->assertResponseOk();
    }
}

Home Controller 就是这样。在大多数情况下,您实际上并不关心您被重定向到哪里,因为这可能会随着时间而改变,您将不得不更改测试。因此,您至少应该做的是检查您是否被重定向,并且只有在您真的认为这对您的测试很重要时才检查更多细节。

让我们看一下身份验证 Controller :

class AuthenticationControllerTest extends TestCase
{
    /**
     * @test
     */
    public function it_shows_the_login_form()
    {
        $response = $this->call('GET', 'login');

        $this->assertTrue($response->isOk());

        // Even though the two lines above may be enough,
        // you could also check for something like this:

        View::shouldReceive('make')->with('login');
    }

    /**
     * @test
     */
    public function it_redirects_back_to_form_if_login_fails()
    {
        $credentials = [
            'email' => 'test@test.com',
            'password' => 'secret',
        ];

        Auth::shouldReceive('attempt')
             ->once()
             ->with($credentials)
             ->andReturn(false);

        $this->call('POST', 'login', $credentials);

        $this->assertRedirectedToAction(
            'AuthenticationController@login', 
            null, 
            ['flash_message']
        );
    }

    /**
     * @test
     */
    public function it_redirects_to_home_page_after_user_logs_in()
    {
        $credentials = [
            'email' => 'test@test.com',
            'password' => 'secret',
        ];

        Auth::shouldReceive('attempt')
             ->once()
             ->with($credentials)
             ->andReturn(true);

        $this->call('POST', 'login', $credentials);

        $this->assertRedirectedTo('home');
    }
}

同样,请始终考虑您真正想要测试的内容。您真的需要知道在哪条路由上触发了哪个 Controller 操作吗?或者返回的 View 名称是什么?实际上,您只需要确保 Controller 确实尝试 执行此操作。您将一些数据传递给它,然后测试它是否按预期运行。

并始终确保您没有尝试测试任何框架功能,例如特定路由是否触发特定操作或 View 是否正确加载。这已经过测试,因此您无需担心。关注应用程序的功能,而不是底层框架。

关于php - Controller 的 Laravel 单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24887777/

相关文章:

php - 比较 php 中的日期时出现奇怪的问题

php - Laravel,管理 Controller - 403 Forbidden

php - 自动为 $fillable 属性赋值 (Laravel 4)

mysql - 如何覆盖所有时间属性

PHP 到 mySQL - 查找插入 ID 时复制条目

php - $_POST 输入数组上的 foreach 返回重复字段

unit-testing - 单元测试 golang 处理程序

node.js - 使用 Promise 处理进行单元测试 - Node.js

php - Android 应用程序将数据发送到 PHP 脚本 - 预期失败

java - EasyMock:无效方法