在对 Laravel 应用程序进行功能测试时跳过授权
Skip authorization while functional testing a Laravel application
是否有内置方法可以在测试控制器时完全跳过授权?
示例控制器:
public function changePassword(Request $request, LdapInterface $ldap)
{
$this->authorize('change-password');
$this->validate($request, [
'pass' => 'min:8|confirmed|weakpass|required',
]);
$success = $ldap->updatePassword($request->get('pass'));
$message = $success ?
'Your e-mail password has been successfully changed' :
'An error occured while trying to change your alumni e-mail password.';
return response()->json(['message' => $message]);
}
我想跳过 change-password
规则,它在 AuthServiceProvider
中定义为:
public function boot(GateContract $gate)
{
$gate->define('change-password', function ($user) {
// Some complex logic here
});
}
我不想添加 smt。像 if (env('APP_ENV') == 'testing') return;
里面的代码。
我不知道有一个,但您可以将该检查移至专用中间件并使用 withoutMiddleware 特性在测试中禁用它。
或者您可以使用 Mockery 模拟应用程序的门实例。 Mockery 有很好的文档记录,所以我建议阅读文档以获取更多详细信息,但设置它看起来像这样:
$mock = Mockery::mock('Illuminate\Contracts\Auth\Access\Gate');
$mock->shouldReceive('authorize')->with('change-password')->once()->andReturn(true);
$this->app->instance('Illuminate\Contracts\Auth\Access\Gate', $mock);
这设置了门合同的模拟,设置了它期望接收的内容以及它应该如何响应,然后将其注入到应用程序中。
来自 laravel documentation :
When testing your application, you may find it convenient to disable
middleware for some of your tests. This will allow you to test your
routes and controller in isolation from any middleware concerns.
Laravel includes a simple WithoutMiddleware
trait that you can use to
automatically disable all middleware for the test class:
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use WithoutMiddleware;
//
}
或者您可以在测试方法中使用 withoutMiddleware()
方法,如下所示:
public function testBasicExample()
{
$this->withoutMiddleware();
$this->visit('/')
->see('Laravel 5');
}
Ps : 因为 Laravel 5.1
其实有一个内置的方式。您可以添加一个 "before" 回调以在实际授权检查之前调用并通过返回 true
:
来绕过检查
\Gate::before(function () {
return true;
});
您应该将此代码段添加到测试的 setUp()
方法或要绕过授权的每个测试方法。
简单多了。
只需将其从路由文件中的所需授权部分中取出即可。
在这个例子中,我需要 AssignmentsController 在没有身份验证的情况下工作,所以我只是将它从 jwt.auth 组中移出:
Route::post('v1/auth/login', 'Api\AuthController@authenticate');
Route::post('v1/auth/sendpassword', 'Api\AuthController@sendPassword');
Route::get('v1/assignments', 'Api\AssignmentsController@getAll');
Route::group(['middleware' => 'jwt.auth'], function() {
Route::post('v1/auth/logout', 'Api\AuthController@logout');
Route::post('v1/shipments', 'Api\ShipmentController@getShipments');
Route::post('v1/assignments/{id}/transfer', 'Api\AssignmentsController@saveAssignment');
Route::get('v1/shipments/assignments/{assignmentId}', 'Api\AssignmentsController@getDetail');
Route::post('v1/shipments/assignments/{id}/upload', 'Api\AssignmentsController@uploadFile');
});
在我的测试中,我添加了一个方法,我可以在测试开始时调用该方法来仅对该测试禁用授权。
添加到您的基础测试中class
public function withoutAuthorization()
{
\Gate::before(function () {
return true;
});
return $this;
}
然后在测试中你可以调用它:
public function testSomeThing()
{
$this->withoutAuthorization();
// any gates will be bypassed
$this->get('/my-protected-endpoint');
}
是否有内置方法可以在测试控制器时完全跳过授权?
示例控制器:
public function changePassword(Request $request, LdapInterface $ldap)
{
$this->authorize('change-password');
$this->validate($request, [
'pass' => 'min:8|confirmed|weakpass|required',
]);
$success = $ldap->updatePassword($request->get('pass'));
$message = $success ?
'Your e-mail password has been successfully changed' :
'An error occured while trying to change your alumni e-mail password.';
return response()->json(['message' => $message]);
}
我想跳过 change-password
规则,它在 AuthServiceProvider
中定义为:
public function boot(GateContract $gate)
{
$gate->define('change-password', function ($user) {
// Some complex logic here
});
}
我不想添加 smt。像 if (env('APP_ENV') == 'testing') return;
里面的代码。
我不知道有一个,但您可以将该检查移至专用中间件并使用 withoutMiddleware 特性在测试中禁用它。
或者您可以使用 Mockery 模拟应用程序的门实例。 Mockery 有很好的文档记录,所以我建议阅读文档以获取更多详细信息,但设置它看起来像这样:
$mock = Mockery::mock('Illuminate\Contracts\Auth\Access\Gate');
$mock->shouldReceive('authorize')->with('change-password')->once()->andReturn(true);
$this->app->instance('Illuminate\Contracts\Auth\Access\Gate', $mock);
这设置了门合同的模拟,设置了它期望接收的内容以及它应该如何响应,然后将其注入到应用程序中。
来自 laravel documentation :
When testing your application, you may find it convenient to disable middleware for some of your tests. This will allow you to test your routes and controller in isolation from any middleware concerns. Laravel includes a simple
WithoutMiddleware
trait that you can use to automatically disable all middleware for the test class:
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use WithoutMiddleware;
//
}
或者您可以在测试方法中使用 withoutMiddleware()
方法,如下所示:
public function testBasicExample()
{
$this->withoutMiddleware();
$this->visit('/')
->see('Laravel 5');
}
Ps : 因为 Laravel 5.1
其实有一个内置的方式。您可以添加一个 "before" 回调以在实际授权检查之前调用并通过返回 true
:
\Gate::before(function () {
return true;
});
您应该将此代码段添加到测试的 setUp()
方法或要绕过授权的每个测试方法。
简单多了。 只需将其从路由文件中的所需授权部分中取出即可。 在这个例子中,我需要 AssignmentsController 在没有身份验证的情况下工作,所以我只是将它从 jwt.auth 组中移出:
Route::post('v1/auth/login', 'Api\AuthController@authenticate');
Route::post('v1/auth/sendpassword', 'Api\AuthController@sendPassword');
Route::get('v1/assignments', 'Api\AssignmentsController@getAll');
Route::group(['middleware' => 'jwt.auth'], function() {
Route::post('v1/auth/logout', 'Api\AuthController@logout');
Route::post('v1/shipments', 'Api\ShipmentController@getShipments');
Route::post('v1/assignments/{id}/transfer', 'Api\AssignmentsController@saveAssignment');
Route::get('v1/shipments/assignments/{assignmentId}', 'Api\AssignmentsController@getDetail');
Route::post('v1/shipments/assignments/{id}/upload', 'Api\AssignmentsController@uploadFile');
});
在我的测试中,我添加了一个方法,我可以在测试开始时调用该方法来仅对该测试禁用授权。
添加到您的基础测试中class
public function withoutAuthorization()
{
\Gate::before(function () {
return true;
});
return $this;
}
然后在测试中你可以调用它:
public function testSomeThing()
{
$this->withoutAuthorization();
// any gates will be bypassed
$this->get('/my-protected-endpoint');
}