单元测试Laravel中间件

时间:2015-07-14 14:20:24

标签: unit-testing laravel-5 middleware

我正在尝试为Laravel中的中间件编写单元测试。有没有人知道一个教程,或者有一个这样的例子?

我一直在编写很多代码,但必须有更好的方法来测试handle方法。

4 个答案:

答案 0 :(得分:13)

使用Laravel 5.2,我通过传递带有输入的请求和带有断言的闭包来对我的中间件进行单元测试。

所以我有一个中间件class GetCommandFromSlack,它将我的Post中的text字段的第一个单词(来自Slack斜杠命令的文本)解析为一个名为command的新字段,然后将text字段修改为不再包含该第一个字。它有一个带有以下签名的方法:public function handle(\Illuminate\Http\Request $request, Closure $next)

我的测试用例看起来像这样:

use App\Http\Middleware\GetCommandFromSlack;
use Illuminate\Http\Request;

class CommandsFromSlackTest extends TestCase
{
  public function testShouldKnowLiftCommand()
  {
    $request = new Illuminate\Http\Request();
    $request->replace([
        'text' => 'lift foo bar baz',
    ]);
    $mw = new \App\Http\Middleware\GetCommandFromSlack;
    $mw->handle($request,function($r) use ($after){
      $this->assertEquals('lift',       $r->input('command'));
      $this->assertEquals('foo bar baz',$r->input('text'));
    });
  }
}

我希望有所帮助!如果我让更复杂的中间件工作,我会尝试更新它。

答案 1 :(得分:3)

要实际测试中间件类本身,您可以这样做:

public function testHandle()
{

    $user = new User(['email'=>'...','name'=>'...']);
    /**
     * setting is_admin to 1 which means the is Admin middleware should 
     * let him pass, but oc depends on your handle() method
     */
    $user->is_admin = 1;        
    $model = $this->app['config']['auth.model'];
    /**
     * assuming you use Eloquent for your User model
     */
    $userProvider = new \Illuminate\Auth\EloquentUserProvider($this->app['hash'], $model);

    $guard = new \Illuminate\Auth\Guard($userProvider, $this->app['session.store']);
    $guard->setUser($user);

    $request = new \Illuminate\Http\Request();        
    $middleware = new \YourApp\Http\Middleware\AuthenticateAdmin($guard);        

    $result = $middleware->handle($request, function(){ return 'can access';});
    $this->assertEquals('can access',$result);

}

答案 2 :(得分:2)

我认为最好的解决方案就是检查中间件之后发生的事情。例如,身份验证中间件:

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\Guard;

class Authenticate {

    /**
     * The Guard implementation.
     *
     * @var Guard
     */
    protected $auth;

    /**
     * Create a new filter instance.
     *
     * @param  Guard  $auth
     * @return void
     */
    public function __construct(Guard $auth)
    {
        $this->auth = $auth;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($this->auth->guest())
        {
            if ($request->ajax())
            {
                return response('Unauthorized.', 401);
            }
            else
            {
                return redirect()->guest('auth/login');
            }
        }

        return $next($request);
    }

}

我的测试单位:

<?php

class AuthenticationTest extends TestCase {

    public function testIAmLoggedIn()
    {
        // Login as someone
        $user = new User(['name' => 'Admin']);
        $this->be($user);

        // Call as AJAX request.
        $this->client->setServerParameter('HTTP_X-Requested-With', 'XMLHttpRequest');
        $this->call('get', '/authpage');

        $this->assertEquals(200, $response->getStatusCode());
    }

}

我会这样做。

答案 3 :(得分:1)

我正在开发一个本地化中间件,它根据URI段设置应用程序区域设置,例如: http://example.com/ar/foo应将应用本地设置为阿拉伯语。我基本上嘲笑Request对象并正常测试。这是我的测试类:

use Illuminate\Http\Request;
use App\Http\Middleware\Localize;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class LocalizeMiddlewareTest extends TestCase
{
    protected $request;
    protected $localize;

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

        config(['locale' => 'en']);
        config(['app.supported_locales' => ['en', 'ar']]);

        $this->request = Mockery::mock(Request::class);

        $this->localize = new Localize;
    }

    /** @test */
    public function it_sets_the_app_locale_from_the_current_uri()
    {
        $this->request->shouldReceive('segment')->once()->andReturn('ar');

        $this->localize->handle($this->request, function () {});

        $this->assertEquals('ar', app()->getLocale());
    }

    /** @test */
    public function it_allows_designating_the_locale_uri_segment()
    {
        $this->request->shouldReceive('segment')->with(2)->once()->andReturn('ar');

        $this->localize->handle($this->request, function () {}, 2);

        $this->assertEquals('ar', app()->getLocale());
    }

    /** @test */
    public function it_throws_an_exception_if_locale_is_unsupported()
    {
        $this->request->shouldReceive('segment')->once()->andReturn('it');
        $this->request->shouldReceive('url')->once()->andReturn('http://example.com/it/foo');

        $this->setExpectedException(
            Exception::class,
            "Locale `it` in URL `http://example.com/it/foo` is not supported."
        );

        $this->localize->handle($this->request, function () {});
    }
}

这是我的中间件类:

namespace App\Http\Middleware;

use Closure;

class Localize
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  integer  $localeUriSegment
     * @return mixed
     */
    public function handle($request, Closure $next, $localeUriSegment = 1)
    {
        $locale = $request->segment($localeUriSegment);

        if (in_array($locale, config('app.supported_locales')))
        {
            app()->setLocale($locale);
        }
        else
        {
            abort(500, "Locale `{$locale}` in URL `".$request->url().'` is not supported.');
        }

        return $next($request);
    }
}

希望有所帮助:)