php - 即使 postman 做对了,测试也无法正确断言请求

标签 php laravel testing laravel-5 laravel-5.5

晚安,我这里有点小麻烦。我是第一次做 TDD,所以我不知道这种行为的根源。这篇文章看起来很长,但主要是因为我复制了大部分相关代码。

案例

顺便说一句,我正在使用 Laravel 作为后端来制作应用程序。

我正在测试具有 admin 角色的 User 可以创建“Facility”对象,但其他用户不能。一些非常基本的东西。

问题

在测试端点时,它让具有角色user(常规角色)的用户创建对象。但是当我尝试使用 Postman 对其进行测试时,它按预期工作:阻止请求。

为了管理 acl,我使用了 Laratrust 包(它运行良好,已经测试过了)。

代码

routes/api.php//这已经有了中间件:auth & api

Route::post('api/v1/facilities', 'FacilityController@store');

App\Htpp\Controllers\FacilityController.php

use App\Http\Requests\Facility\CreateFacilityRequest;
use App\Http\Resources\FacilityResource;
use App\Repositories\FacilityRepository;
use App\Services\ImageService;
use Illuminate\Http\Response;

// some code

/**
 * Create a new Facility
 *
 * @param CreateFacilityRequest $request
 * @return \Illuminate\Http\JsonResponse
 */
public function store(CreateFacilityRequest $request)
{
    $data = $request->only(['name']);
    $file = $request->file('image');
    $data['image'] = ImageService::storeAs('images/facilities', $file, 'friendly', $data['name']);

    $facility = $this->facilityRepository->create($data);

    return response()->json([
        "message" => "The facility has been added.",
        "data"    => new FacilityResource($facility)
    ], Response::HTTP_CREATED);
}

应用\Http\Requests\Facility\CreateFacilityRequest.php

class CreateFacilityRequest extends FormRequest {

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return auth()->user()->can('create-facilities');
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name'  => 'required|string|unique:facilities,name',
            'image' => 'required|image'
        ];
    }
}

最后,这是我的测试:

测试\Feature\FacilityTest.php

/**
     * @test
     * Test for: a Facility can be registered only by an admin.
     */
    public function a_facility_can_be_registered_only_by_an_admin()
    {
        /** Given a correct information for a facility */
        \Storage::fake('public');
        $data = ["name" => "Facility A", 'image' => UploadedFile::fake()->image('facility-a.jpg') ];

        /** When the request is made by an admin */
        $admin = $this->createUser([], 'admin');
        $response = $this->apiAs($admin, 'POST','/api/v1/facilities', $data);

        /** Then the facility should be registered */
        $response->assertStatus(Response::HTTP_CREATED); // 201

        /** When the request is made by somebody else */
        $data = ["name" => "Facility B", 'image' =>UploadedFile::fake()->image('facility-b.jpg') ];
        $regular_user = $this->createUser([], 'user');
        $response = $this->apiAs($regular_user, 'POST','/api/v1/facilities', $data);

        /** Then the request should be declined */
        $this->assertTrue($regular_user->hasRole('user'));
        $this->assertFalse($regular_user->can('create-facilities'));

        $response->assertStatus(Response::HTTP_FORBIDDEN); // 403
        \Storage::disk('facilities')->assertMissing('facility-b.jpg');
    }

所有的断言都被证实了,除了这个:

$response->assertStatus(Response::HTTP_FORBIDDEN); // 403

输出是这样的:

Expected status code 403 but received 201.

Failed asserting that false is true.

Time: 447 ms, Memory: 20.00MB

FAILURES! Tests: 1, Assertions: 4, Failures: 1.

Process finished with exit code 1


当我 dd($response->json()) 它返回成功调用的常规 json。但在 Postman 中它返回正确的:

{
    "message" : "Unauthorized" // with status code 403
}

有人知道为什么吗?


更新

protected 函数 apiAs()

protected function apiAs($user, $method, $uri, array $data = [], array $headers = []) : TestResponse
    {
        $headers = array_merge([
            'Authorization' => 'Bearer '.\JWTAuth::fromUser($user),
            'Accept' => 'application/json'
        ], $headers);

        return $this->api($method, $uri, $data, $headers);
    }


    protected function api($method, $uri, array $data = [], array $headers = [])
    {
        return $this->json($method, $uri, $data, $headers);
    }

最佳答案

这是因为您正在使用 jwt-authapiAs() 方法缓存与此行上的响应关联的用户标识符:

'Authorization' => 'Bearer '.\JWTAuth::fromUser($user),

这会导致您的 $response 变量,在您作为普通用户第二次获取 API 时,为管理员返回第一个缓存数据。

我会将这些断言分成单独的测试,并且您的命名目前已关闭 a_facility_can_be_registered_only_by_an_admin()a_facility_cannot_be_registered_by_a_user_that_is_not_an_admin() 可能是一个适用的名称并绕过此缓存。

关于php - 即使 postman 做对了,测试也无法正确断言请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48917286/

相关文章:

php - 根据mysql数据库检查php登录表单

php - 在特定位置的多维数组中添加多维数组

javascript - 在laravel中动态添加输入字段并将数据保存到数据库

php - “Can' t将图像数据写入路径”-Laravel Image Intervention

php - 如何在 Laravel 5.2 中编写 >= Eloquent 数据库查询

php - 图像在 IE 中未正确对齐

laravel中mysql和mongodb的关系

ruby-on-rails - 如何使用 Capybara 确认 javascript 弹出窗口?

ruby-on-rails - Rails 形式测试 : post directly or through form?

php - 单元测试应该遵循 PSR 吗?