如何使用 Laravel 测试授权重定向?

How to test an authorization redirect with Laravel?

我已经手动测试了我想要的场景:

管理员用户可以转到站点的 /codes 部分。 普通用户被重定向 (302) 回到 /dashboard 并在他们转到 /qr.

时收到消息 Sorry you are not allowed there

手动测试通过,但 laravel 测试失败。

我正在使用 laravel 5.1

管理员用户测试:

public function testAdminViewCodes()
    {
        //create an admin user
        $user = factory(App\User::class, 'admin')->create();

        $this->actingAs($user)
            ->visit('/codes')
            ->seePageIs('/codes')
            ->see('Codes');
    }

普通用户测试:

    public function testNormalViewCodesFail()
    {
        //create a normal user
        $normal_user = factory(App\User::class)->create();

        //TODO: Fix this failing test FFS

        $this->actingAs($normal_user)
             ->visit('/qr')
             ->seePageIs('/dashboard')
             ->see('Sorry you are not allowed there');
}

测试结果;

There was 1 failure:

1) AdminTest::testNormalViewQRCodesFail
Did not land on expected page [http://localhost/dashboard].

Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'http://localhost/dashboard'
+'http://localhost/codes'

我认为工厂可能有问题,似乎总是在创建管理员用户:

$factory->define(App\User::class, function (Faker\Generator $faker) {
    return [
        'email' => $faker->email,
        'password' => bcrypt(str_random(10)),
        'remember_token' => str_random(10),
        'is_admin' => false,
    ];
});

$factory->defineAs(App\User::class, 'admin', function ($faker) use ($factory) {
    $user = $factory->raw(App\User::class);

    return array_merge($user, ['is_admin' => true]);
});

很抱歉这个问题太长了,但还有另一个相关的问题。我正在使用 middleware 来测试用户是否是管理员:

<?php

namespace RMS\Http\Middleware;

use Closure;

class IsAdminMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (app()->env === 'testing') {
            return $next($request);
        }

        if (! $request->user()->isAdmin()) {
          return redirect()->route('dashboard')
              ->with('message', 'Sorry you are not allowed there');
        }

        return $next($request);
    }
}

Kernel.php中:

protected $routeMiddleware = [
        'auth' => \RMS\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'guest' => \RMS\Http\Middleware\RedirectIfAuthenticated::class,
        'isadmin' => \RMS\Http\Middleware\IsAdminMiddleware::class,
    ];

并应用于路线:

Route::group(['middleware' => ['auth', 'isadmin']], function()
{
    Route::resource('user', 'UserController');
});

中间件被忽略了吗?我确定不添加 use WithoutMiddleware; 语句。

我建议使用 Authenticate a User Instance Auth::login($user); 有关详细信息,请阅读 here

此方法适用于Laravel5.x及

以上

您有两个选择:

  • 最好为用户工厂创建测试,比如它可以生成你想要的用户类型
  • 在用户生成后中断调试器以手动检查它

我建议你创建测试,因为你现在有疑问,将来有可能不小心破坏工厂代码,因为它不是那么明显。

顺便说一句:unit tests are not meant to be user experience tests. For that is would be acceptance or functional testing. One of the more popular tools for that is codeception. It combined with phantomjs or selenium 可以模拟浏览器会话并获得完整的用户体验呈现。

根据 http://codeception.com/docs/01-Introduction 文档中提供的文档:

验收测试:'Acceptance tests can cover standard but complex scenarios from a user’s perspective. With acceptance tests you can be confident that users, following all defined scenarios, won’t get errors.'

功能测试:'functional tests you emulate a web request ($_GET and $_POST variables) and send it into your application which returns HTML response. '

单元测试:'Testing pieces of code before coupling them together is highly important as well. This way you can be sure that some deeply hidden feature still works, even if it was not covered by functional or acceptance tests. This also proves that you produced stable and testable code.'