Skip to content

HTTP 测试

介绍

Laravel 提供了一个非常流畅的 API,用于向应用程序发出 HTTP 请求并检查输出。例如,请查看下面定义的测试:

php
<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ExampleTest extends TestCase
{
    /**
     * 一个基本的测试示例。
     *
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

get 方法向应用程序发出 GET 请求,而 assertStatus 方法断言返回的响应应具有给定的 HTTP 状态码。除了这个简单的断言,Laravel 还包含多种断言,用于检查响应头、内容、JSON 结构等。

自定义请求头

您可以使用 withHeaders 方法在请求发送到应用程序之前自定义请求的头。这允许您向请求添加任何自定义头:

php
<?php

class ExampleTest extends TestCase
{
    /**
     * 一个基本的功能测试示例。
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->withHeaders([
            'X-Header' => 'Value',
        ])->json('POST', '/user', ['name' => 'Sally']);

        $response
            ->assertStatus(201)
            ->assertJson([
                'created' => true,
            ]);
    }
}
lightbulb

在运行测试时,CSRF 中间件会自动禁用。

会话 / 认证

Laravel 提供了几个助手,用于在 HTTP 测试期间处理会话。首先,您可以使用 withSession 方法将会话数据设置为给定的数组。这对于在向应用程序发出请求之前加载会话数据非常有用:

php
<?php

class ExampleTest extends TestCase
{
    public function testApplication()
    {
        $response = $this->withSession(['foo' => 'bar'])
                         ->get('/');
    }
}

当然,会话的一个常见用途是为认证用户维护状态。actingAs 助手方法提供了一种简单的方法来将给定用户认证为当前用户。例如,我们可以使用 模型工厂 来生成和认证用户:

php
<?php

use App\User;

class ExampleTest extends TestCase
{
    public function testApplication()
    {
        $user = factory(User::class)->create();

        $response = $this->actingAs($user)
                         ->withSession(['foo' => 'bar'])
                         ->get('/');
    }
}

您还可以通过将守卫名称作为第二个参数传递给 actingAs 方法来指定应使用哪个守卫来认证给定用户:

php
$this->actingAs($user, 'api')

测试 JSON API

Laravel 还提供了几个助手,用于测试 JSON API 及其响应。例如,可以使用 jsongetpostputpatchdelete 方法发出具有各种 HTTP 动词的请求。您还可以轻松地将数据和头传递给这些方法。首先,让我们编写一个测试,以向 /user 发出 POST 请求并断言返回了预期的数据:

php
<?php

class ExampleTest extends TestCase
{
    /**
     * 一个基本的功能测试示例。
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->json('POST', '/user', ['name' => 'Sally']);

        $response
            ->assertStatus(201)
            ->assertJson([
                'created' => true,
            ]);
    }
}
lightbulb

assertJson 方法将响应转换为数组,并利用 PHPUnit::assertArraySubset 来验证给定数组是否存在于应用程序返回的 JSON 响应中。因此,如果 JSON 响应中有其他属性,只要给定的片段存在,此测试仍将通过。

验证精确的 JSON 匹配

如果您想验证给定数组与应用程序返回的 JSON 是精确匹配的,您应该使用 assertExactJson 方法:

php
<?php

class ExampleTest extends TestCase
{
    /**
     * 一个基本的功能测试示例。
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->json('POST', '/user', ['name' => 'Sally']);

        $response
            ->assertStatus(201)
            ->assertExactJson([
                'created' => true,
            ]);
    }
}

测试文件上传

Illuminate\Http\UploadedFile 类提供了一个 fake 方法,可用于生成用于测试的虚拟文件或图像。这与 Storage facade 的 fake 方法结合使用,大大简化了文件上传的测试。例如,您可以结合这两个功能轻松测试头像上传表单:

php
<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ExampleTest extends TestCase
{
    public function testAvatarUpload()
    {
        Storage::fake('avatars');

        $file = UploadedFile::fake()->image('avatar.jpg');

        $response = $this->json('POST', '/avatar', [
            'avatar' => $file,
        ]);

        // 断言文件已存储...
        Storage::disk('avatars')->assertExists($file->hashName());

        // 断言文件不存在...
        Storage::disk('avatars')->assertMissing('missing.jpg');
    }
}

虚拟文件自定义

在使用 fake 方法创建文件时,您可以指定图像的宽度、高度和大小,以便更好地测试您的验证规则:

php
UploadedFile::fake()->image('avatar.jpg', $width, $height)->size(100);

除了创建图像,您还可以使用 create 方法创建任何其他类型的文件:

php
UploadedFile::fake()->create('document.pdf', $sizeInKilobytes);

可用的断言

响应断言

Laravel 为您的 PHPUnit 测试提供了多种自定义断言方法。这些断言可以在从 jsongetpostputdelete 测试方法返回的响应上访问:

assertCookie

断言响应包含给定的 cookie:

php
$response->assertCookie($cookieName, $value = null);

assertCookieExpired

断言响应包含给定的 cookie 并且已过期:

php
$response->assertCookieExpired($cookieName);

assertCookieNotExpired

断言响应包含给定的 cookie 并且未过期:

php
$response->assertCookieNotExpired($cookieName);

assertCookieMissing

断言响应不包含给定的 cookie:

php
$response->assertCookieMissing($cookieName);

assertDontSee

断言给定的字符串不包含在响应中:

php
$response->assertDontSee($value);

assertDontSeeText

断言给定的字符串不包含在响应文本中:

php
$response->assertDontSeeText($value);

assertExactJson

断言响应包含给定 JSON 数据的精确匹配:

php
$response->assertExactJson(array $data);

assertForbidden

断言响应具有禁止状态码:

php
$response->assertForbidden();

assertHeader

断言响应中存在给定的头:

php
$response->assertHeader($headerName, $value = null);

assertHeaderMissing

断言响应中不存在给定的头:

php
$response->assertHeaderMissing($headerName);

assertJson

断言响应包含给定的 JSON 数据:

php
$response->assertJson(array $data);

assertJsonCount

断言响应 JSON 在给定键处有一个具有预期项目数的数组:

php
$response->assertJsonCount($count, $key = null);

assertJsonFragment

断言响应包含给定的 JSON 片段:

php
$response->assertJsonFragment(array $data);

assertJsonMissing

断言响应不包含给定的 JSON 片段:

php
$response->assertJsonMissing(array $data);

assertJsonMissingExact

断言响应不包含精确的 JSON 片段:

php
$response->assertJsonMissingExact(array $data);

assertJsonStructure

断言响应具有给定的 JSON 结构:

php
$response->assertJsonStructure(array $structure);

assertJsonValidationErrors

断言响应具有给定键的 JSON 验证错误:

php
$response->assertJsonValidationErrors($keys);

assertLocation

断言响应在 Location 头中具有给定的 URI 值:

php
$response->assertLocation($uri);

assertNotFound

断言响应具有未找到状态码:

php
$response->assertNotFound();

assertOk

断言响应具有 200 状态码:

php
$response->assertOk();

assertPlainCookie

断言响应包含给定的 cookie(未加密):

php
$response->assertPlainCookie($cookieName, $value = null);

assertRedirect

断言响应是重定向到给定 URI:

php
$response->assertRedirect($uri);

assertSee

断言给定的字符串包含在响应中:

php
$response->assertSee($value);

assertSeeInOrder

断言给定的字符串按顺序包含在响应中:

php
$response->assertSeeInOrder(array $values);

assertSeeText

断言给定的字符串包含在响应文本中:

php
$response->assertSeeText($value);

assertSeeTextInOrder

断言给定的字符串按顺序包含在响应文本中:

php
$response->assertSeeTextInOrder(array $values);

assertSessionHas

断言会话包含给定的数据:

php
$response->assertSessionHas($key, $value = null);

assertSessionHasAll

断言会话具有给定的值列表:

php
$response->assertSessionHasAll(array $data);

assertSessionHasErrors

断言会话包含给定字段的错误:

php
$response->assertSessionHasErrors(array $keys, $format = null, $errorBag = 'default');

assertSessionHasErrorsIn

断言会话具有给定的错误:

php
$response->assertSessionHasErrorsIn($errorBag, $keys = [], $format = null);

assertSessionHasNoErrors

断言会话没有错误:

php
$response->assertSessionHasNoErrors();

assertSessionMissing

断言会话不包含给定的键:

php
$response->assertSessionMissing($key);

assertStatus

断言响应具有给定的代码:

php
$response->assertStatus($code);

assertSuccessful

断言响应具有成功的状态码:

php
$response->assertSuccessful();

assertViewHas

断言响应视图被赋予了一段数据:

php
$response->assertViewHas($key, $value = null);

assertViewHasAll

断言响应视图具有给定的数据列表:

php
$response->assertViewHasAll(array $data);

assertViewIs

断言给定的视图由路由返回:

php
$response->assertViewIs($value);

assertViewMissing

断言响应视图缺少一段绑定数据:

php
$response->assertViewMissing($key);

认证断言

Laravel 还为您的 PHPUnit 测试提供了多种与认证相关的断言:

方法描述
$this->assertAuthenticated($guard = null);断言用户已认证。
$this->assertGuest($guard = null);断言用户未认证。
$this->assertAuthenticatedAs($user, $guard = null);断言给定用户已认证。
$this->assertCredentials(array $credentials, $guard = null);断言给定的凭据有效。
$this->assertInvalidCredentials(array $credentials, $guard = null);断言给定的凭据无效。