HTTP 测试

简介

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

  • Pest

  • PHPUnit

<?php

test('the application returns a successful response', function () {
    $response = $this->get('/');

    $response->assertStatus(200);
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     */
    public function test_the_application_returns_a_successful_response(): void
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

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

发送请求

要向您的应用程序发起请求,您可以在测试中调用 getpostputpatchdelete 方法。这些方法并不会真正发出“真实”的 HTTP 请求到您的应用程序,而是内部模拟整个网络请求。

这些测试请求方法返回的不是 Illuminate\Http\Response 实例,而是 Illuminate\Testing\TestResponse 实例,该实例提供了【多种有用的断言】,允许您检查应用程序的响应:

  • Pest

  • PHPUnit

<?php

test('basic request', function () {
    $response = $this->get('/');

    $response->assertStatus(200);
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     */
    public function test_a_basic_request(): void
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

一般来说,每个测试应该只发起一次请求。如果在单个测试方法中执行多个请求,可能会导致意外的行为。

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

自定义请求头

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

  • Pest

  • PHPUnit

<?php

test('interacting with headers', function () {
    $response = $this->withHeaders([
        'X-Header' => 'Value',
    ])->post('/user', ['name' => 'Sally']);

    $response->assertStatus(201);
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic functional test example.
     */
    public function test_interacting_with_headers(): void
    {
        $response = $this->withHeaders([
            'X-Header' => 'Value',
        ])->post('/user', ['name' => 'Sally']);

        $response->assertStatus(201);
    }
}

Cookies

您可以使用 withCookiewithCookies 方法在发起请求之前设置 cookie 值。withCookie 方法接受一个 cookie 名称和值作为两个参数,而 withCookies 方法接受一个名称/值对的数组:

  • Pest

  • PHPUnit

<?php

test('interacting with cookies', function () {
    $response = $this->withCookie('color', 'blue')->get('/');

    $response = $this->withCookies([
        'color' => 'blue',
        'name' => 'Taylor',
    ])->get('/');

    //
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    public function test_interacting_with_cookies(): void
    {
        $response = $this->withCookie('color', 'blue')->get('/');

        $response = $this->withCookies([
            'color' => 'blue',
            'name' => 'Taylor',
        ])->get('/');

        //
    }
}

会话 / 认证

Laravel 提供了多个辅助方法,用于在 HTTP 测试过程中与会话进行交互。首先,您可以使用 withSession 方法将会话数据设置为给定的数组。在发起请求之前,这对于加载会话数据非常有用:

  • Pest

  • PHPUnit

<?php

test('interacting with the session', function () {
    $response = $this->withSession(['banned' => false])->get('/');

    //
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    public function test_interacting_with_the_session(): void
    {
        $response = $this->withSession(['banned' => false])->get('/');

        //
    }
}

Laravel 的会话通常用于维护当前认证用户的状态。因此,actingAs 辅助方法提供了一种简单的方式来将指定用户认证为当前用户。例如,我们可以使用【模型工厂】生成并认证一个用户:

  • Pest

  • PHPUnit

<?php

use App\Models\User;

test('an action that requires authentication', function () {
    $user = User::factory()->create();

    $response = $this->actingAs($user)
                     ->withSession(['banned' => false])
                     ->get('/');

    //
});
<?php

namespace Tests\Feature;

use App\Models\User;
use Tests\TestCase;

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

        $response = $this->actingAs($user)
                         ->withSession(['banned' => false])
                         ->get('/');

        //
    }
}

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

$this->actingAs($user, 'web')

调试响应

在向应用程序发起测试请求后,您可以使用 dumpdumpHeadersdumpSession 方法来检查和调试响应内容:

  • Pest

  • PHPUnit

<?php

test('basic test', function () {
    $response = $this->get('/');

    $response->dumpHeaders();

    $response->dumpSession();

    $response->dump();
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     */
    public function test_basic_test(): void
    {
        $response = $this->get('/');

        $response->dumpHeaders();

        $response->dumpSession();

        $response->dump();
    }
}

另外,您也可以使用 ddddHeadersddSession 方法来显示响应信息并停止执行:

  • Pest

  • PHPUnit

<?php

test('basic test', function () {
    $response = $this->get('/');

    $response->ddHeaders();

    $response->ddSession();

    $response->dd();
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     */
    public function test_basic_test(): void
    {
        $response = $this->get('/');

        $response->ddHeaders();

        $response->ddSession();

        $response->dd();
    }
}

异常处理

有时,您可能需要测试您的应用程序是否抛出了特定的异常。为此,您可以通过 Exceptions facade "假装" 异常处理器。假装异常处理器后,您可以使用 assertReportedassertNotReported 方法来断言在请求过程中抛出的异常:

  • Pest

  • PHPUnit

<?php

use App\Exceptions\InvalidOrderException;
use Illuminate\Support\Facades\Exceptions;

test('exception is thrown', function () {
    Exceptions::fake();

    $response = $this->get('/order/1');

    // Assert an exception was thrown...
    Exceptions::assertReported(InvalidOrderException::class);

    // Assert against the exception...
    Exceptions::assertReported(function (InvalidOrderException $e) {
        return $e->getMessage() === 'The order was invalid.';
    });
});
<?php

namespace Tests\Feature;

use App\Exceptions\InvalidOrderException;
use Illuminate\Support\Facades\Exceptions;
use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     */
    public function test_exception_is_thrown(): void
    {
        Exceptions::fake();

        $response = $this->get('/');

        // Assert an exception was thrown...
        Exceptions::assertReported(InvalidOrderException::class);

        // Assert against the exception...
        Exceptions::assertReported(function (InvalidOrderException $e) {
            return $e->getMessage() === 'The order was invalid.';
        });
    }
}

您还可以使用 assertNotReportedassertNothingReported 方法来断言在请求过程中没有抛出指定的异常,或没有抛出任何异常:

Exceptions::assertNotReported(InvalidOrderException::class);

Exceptions::assertNothingReported();

如果您希望完全禁用异常处理,可以在发起请求之前调用 withoutExceptionHandling 方法:

$response = $this->withoutExceptionHandling()->get('/');

此外,如果您希望确保您的应用程序没有使用 PHP 语言或您的应用程序使用的库中已弃用的功能,可以在发起请求之前调用 withoutDeprecationHandling 方法。当禁用弃用处理时,弃用警告将被转换为异常,从而导致测试失败:

$response = $this->withoutDeprecationHandling()->get('/');

assertThrows 方法可用于断言给定闭包内的代码抛出指定类型的异常:

$this->assertThrows(
    fn () => (new ProcessOrder)->execute(),
    OrderInvalid::class
);

如果您想检查并对抛出的异常进行断言,可以将一个闭包作为第二个参数传递给 assertThrows 方法:

$this->assertThrows(
    fn () => (new ProcessOrder)->execute(),
    fn (OrderInvalid $e) => $e->orderId() === 123;
);

测试 JSON API

Laravel 还提供了几个帮助函数,用于测试 JSON API 及其响应。例如,jsongetJsonpostJsonputJsonpatchJsondeleteJsonoptionsJson 方法可以用于发送带有各种 HTTP 动词的 JSON 请求。您还可以轻松地向这些方法传递数据和头部信息。让我们开始写一个测试,向 /api/user 发送 POST 请求,并断言返回了预期的 JSON 数据:

  • Pest

  • PHPUnit

<?php

test('making an api request', function () {
    $response = $this->postJson('/api/user', ['name' => 'Sally']);

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

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic functional test example.
     */
    public function test_making_an_api_request(): void
    {
        $response = $this->postJson('/api/user', ['name' => 'Sally']);

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

此外,JSON 响应数据可以作为响应的数组变量进行访问,这使得检查 JSON 响应中的单个值变得非常方便:

  • Pest

  • PHPUnit

expect($response['created'])->toBeTrue();
$this->assertTrue($response['created']);

assertJson 方法会将响应转换为数组,以验证给定的数组是否存在于应用程序返回的 JSON 响应中。因此,如果 JSON 响应中还有其它属性,只要给定的片段存在,测试仍然会通过。

断言精确的 JSON 匹配

如前所述,assertJson 方法可以用来断言某个 JSON 片段是否存在于响应中。如果您希望验证给定的数组是否与应用程序返回的 JSON 完全匹配,应该使用 assertExactJson 方法:

  • Pest

  • PHPUnit

<?php

test('asserting an exact json match', function () {
    $response = $this->postJson('/user', ['name' => 'Sally']);

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

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic functional test example.
     */
    public function test_asserting_an_exact_json_match(): void
    {
        $response = $this->postJson('/user', ['name' => 'Sally']);

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

断言 JSON 路径

如果您希望验证 JSON 响应中在指定路径下是否包含给定的数据,可以使用 assertJsonPath 方法:

  • Pest

  • PHPUnit

<?php

test('asserting a json path value', function () {
    $response = $this->postJson('/user', ['name' => 'Sally']);

    $response
        ->assertStatus(201)
        ->assertJsonPath('team.owner.name', 'Darian');
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic functional test example.
     */
    public function test_asserting_a_json_paths_value(): void
    {
        $response = $this->postJson('/user', ['name' => 'Sally']);

        $response
            ->assertStatus(201)
            ->assertJsonPath('team.owner.name', 'Darian');
    }
}

assertJsonPath 方法也接受一个闭包,您可以使用它动态确定断言是否应该通过:

$response->assertJsonPath('team.owner.name', fn (string $name) => strlen($name) >= 3);

流式 JSON 测试

Laravel 还提供了一种流畅的方式来测试您的应用程序的 JSON 响应。要开始使用,请将一个闭包传递给 assertJson 方法。这个闭包会使用 Illuminate\Testing\Fluent\AssertableJson 实例进行调用,您可以使用该实例对应用程序返回的 JSON 进行断言。where 方法可用于对 JSON 的特定属性进行断言,而 missing 方法可用于断言某个属性在 JSON 中缺失:

  • Pest

  • PHPUnit

use Illuminate\Testing\Fluent\AssertableJson;

test('fluent json', function () {
    $response = $this->getJson('/users/1');

    $response
        ->assertJson(fn (AssertableJson $json) =>
            $json->where('id', 1)
                 ->where('name', 'Victoria Faith')
                 ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                 ->whereNot('status', 'pending')
                 ->missing('password')
                 ->etc()
        );
});
use Illuminate\Testing\Fluent\AssertableJson;

/**
 * A basic functional test example.
 */
public function test_fluent_json(): void
{
    $response = $this->getJson('/users/1');

    $response
        ->assertJson(fn (AssertableJson $json) =>
            $json->where('id', 1)
                 ->where('name', 'Victoria Faith')
                 ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                 ->whereNot('status', 'pending')
                 ->missing('password')
                 ->etc()
        );
}

理解 etc 方法

在上面的示例中,您可能注意到在断言链的末尾调用了 etc 方法。此方法告诉 Laravel,JSON 对象中可能还存在其它属性。如果没有使用 etc 方法,如果 JSON 对象中存在您没有进行断言的其它属性,测试将失败。

此行为的目的是防止您在 JSON 响应中无意暴露敏感信息,强制您显式地对属性进行断言,或者通过 etc 方法显式地允许额外的属性。

然而,您应该注意,未在断言链中包含 etc 方法并不能确保不会向嵌套的 JSON 数组添加额外的属性。etc 方法仅确保在调用 etc 方法的嵌套级别上没有额外的属性存在。

断言属性的存在与缺失

要断言某个属性存在或缺失,您可以使用 hasmissing 方法:

$response->assertJson(fn (AssertableJson $json) =>
    $json->has('data')
         ->missing('message')
);

此外,hasAllmissingAll 方法允许同时断言多个属性的存在或缺失:

$response->assertJson(fn (AssertableJson $json) =>
    $json->hasAll(['status', 'data'])
         ->missingAll(['message', 'code'])
);

您可以使用 hasAny 方法来判断给定属性列表中至少有一个属性存在:

$response->assertJson(fn (AssertableJson $json) =>
    $json->has('status')
         ->hasAny('data', 'message', 'code')
);

断言 JSON 集合

通常,您的路由会返回一个包含多个项目的 JSON 响应,例如多个用户:

Route::get('/users', function () {
    return User::all();
});

在这些情况下,我们可以使用流畅的 JSON 对象的 has 方法对响应中的用户进行断言。例如,让我们断言 JSON 响应中包含三个用户。接着,我们将使用 first 方法对集合中的第一个用户进行一些断言。first 方法接受一个闭包,该闭包接收另一个可断言的 JSON 字符串,您可以用它来对 JSON 集合中的第一个对象进行断言:

$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has(3)
             ->first(fn (AssertableJson $json) =>
                $json->where('id', 1)
                     ->where('name', 'Victoria Faith')
                     ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                     ->missing('password')
                     ->etc()
             )
    );

限定 JSON 集合的断言范围

有时,您的应用程序的路由会返回带有命名键的 JSON 集合:

Route::get('/users', function () {
    return [
        'meta' => [...],
        'users' => User::all(),
    ];
});

在测试这些路由时,您可以使用 has 方法断言集合中项目的数量。此外,您还可以使用 has 方法来限定断言链的范围:

$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has('meta')
             ->has('users', 3)
             ->has('users.0', fn (AssertableJson $json) =>
                $json->where('id', 1)
                     ->where('name', 'Victoria Faith')
                     ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                     ->missing('password')
                     ->etc()
             )
    );

然而,您也可以通过对 has 方法传递一个闭包作为其第三个参数,来对集合中的第一个项目进行单次调用。当这样做时,闭包会自动被调用并限定在集合中的第一个项目:

$response
    ->assertJson(fn (AssertableJson $json) =>
        $json->has('meta')
             ->has('users', 3, fn (AssertableJson $json) =>
                $json->where('id', 1)
                     ->where('name', 'Victoria Faith')
                     ->where('email', fn (string $email) => str($email)->is('victoria@gmail.com'))
                     ->missing('password')
                     ->etc()
             )
    );

断言 JSON 类型

有时,您可能只想断言 JSON 响应中的属性是某种特定类型。Illuminate\Testing\Fluent\AssertableJson 类提供了 whereTypewhereAllType 方法,来帮助您完成这项任务:

$response->assertJson(fn (AssertableJson $json) =>
    $json->whereType('id', 'integer')
         ->whereAllType([
            'users.0.name' => 'string',
            'meta' => 'array'
        ])
);

您可以通过 | 字符指定多个类型,或者将类型数组作为第二个参数传递给 whereType 方法。如果响应值的类型是列出的任何类型,断言将通过:

$response->assertJson(fn (AssertableJson $json) =>
    $json->whereType('name', 'string|null')
         ->whereType('id', ['string', 'integer'])
);

whereTypewhereAllType 方法支持以下类型:stringintegerdoublebooleanarraynull

测试文件上传

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

  • Pest

  • PHPUnit

<?php

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

test('avatars can be uploaded', function () {
    Storage::fake('avatars');

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

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

    Storage::disk('avatars')->assertExists($file->hashName());
});
<?php

namespace Tests\Feature;

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;

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

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

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

        Storage::disk('avatars')->assertExists($file->hashName());
    }
}

如果您希望断言某个文件不存在,您可以使用 Storage 门面提供的 assertMissing 方法:

Storage::fake('avatars');

// ...

Storage::disk('avatars')->assertMissing('missing.jpg');

假文件定制

在使用 UploadedFile 类提供的 fake 方法创建文件时,您可以指定图像的宽度、高度和大小(以千字节为单位),以便更好地测试应用程序的验证规则:

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

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

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

如果需要,您可以传递一个 $mimeType 参数,以显式定义文件应该返回的 MIME 类型:

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

测试视图

Laravel 还允许您在不对应用程序进行模拟 HTTP 请求的情况下渲染视图。要实现这一点,您可以在测试中调用 view 方法。该方法接受视图名称和一个可选的数组数据。该方法返回一个 Illuminate\Testing\TestView 实例,它提供了多种方法,方便您对视图内容进行断言:

  • Pest

  • PHPUnit

<?php

test('a welcome view can be rendered', function () {
    $view = $this->view('welcome', ['name' => 'Taylor']);

    $view->assertSee('Taylor');
});
<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    public function test_a_welcome_view_can_be_rendered(): void
    {
        $view = $this->view('welcome', ['name' => 'Taylor']);

        $view->assertSee('Taylor');
    }
}

TestView 类提供以下断言方法:assertSeeassertSeeInOrderassertSeeTextassertSeeTextInOrderassertDontSeeassertDontSeeText

如果需要,您可以通过将 TestView 实例强制转换为字符串,获取原始渲染的视图内容:

$contents = (string) $this->view('welcome');

共享错误

某些视图可能依赖于 Laravel 提供的全局错误袋中共享的错误。要为错误袋填充错误信息,您可以使用 withViewErrors 方法:

$view = $this->withViewErrors([
    'name' => ['Please provide a valid name.']
])->view('form');

$view->assertSee('Please provide a valid name.');

渲染 Blade 和组件

如果需要,您可以使用 blade 方法来评估和渲染原始的 Blade 字符串。与 view 方法类似,blade 方法返回一个 Illuminate\Testing\TestView 实例:

$view = $this->blade(
    '<x-component :name="$name" />',
    ['name' => 'Taylor']
);

$view->assertSee('Taylor');

您可以使用 component 方法来评估和渲染 Blade 组件。component 方法返回一个 Illuminate\Testing\TestComponent 实例:

$view = $this->component(Profile::class, ['name' => 'Taylor']);

$view->assertSee('Taylor');

可用的断言

响应断言

Laravel 的 Illuminate\Testing\TestResponse 类提供了多种自定义断言方法,您可以在测试应用程序时使用。这些断言可以在 jsongetpostputdelete 测试方法返回的响应上进行访问:

assertBadRequest

断言响应具有 “bad 请求” (400) HTTP 状态码:

$response->assertBadRequest();

assertAccepted

断言响应具有 “已接受” (202) HTTP 状态码:

$response->assertAccepted();

assertConflict

断言响应具有 “冲突” (409) HTTP 状态码:

$response->assertConflict();

assertCookie

断言响应包含给定的 cookie

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

assertCookieExpired

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

$response->assertCookieExpired($cookieName);

assertCookieNotExpired

断言响应包含给定的 cookie 并且它没有过期:

$response->assertCookieNotExpired($cookieName);

assertCookieMissing

断言响应不包含给定的 cookie

$response->assertCookieMissing($cookieName);

assertCreated

断言响应具有 201 HTTP 状态码:

$response->assertCreated();

assertDontSee

断言给定的字符串不包含在应用程序返回的响应中。除非你传递第二个参数为 false,否则此断言会自动转义给定的字符串:

$response->assertDontSee($value, $escaped = true);

assertDontSeeText

断言给定的字符串不包含在响应文本中。除非你传递第二个参数为 false,否则此断言会自动转义给定的字符串。此方法会将响应内容传递给 strip_tags PHP 函数,然后再进行断言:

$response->assertDontSeeText($value, $escaped = true);

assertDownload

断言响应是一个 “下载”。通常,这意味着返回的响应是一个 Response::download 响应、BinaryFileResponseStorage::download 响应:

$response->assertDownload();

如果需要,您可以断言可下载的文件具有给定的文件名:

$response->assertDownload('image.jpg');

assertExactJson

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

$response->assertExactJson(array $data);

assertExactJsonStructure

断言响应包含给定 JSON 结构的精确匹配:

$response->assertExactJsonStructure(array $data);

此方法是 assertJsonStructure 的一个更严格的变体。与 assertJsonStructure 相比,如果响应包含任何未显式包含在预期 JSON 结构中的键,则此方法会失败。

assertForbidden

断言响应具有 “禁止访问” (403) HTTP 状态码:

$response->assertForbidden();

assertFound

断言响应具有 “已找到” (302) HTTP 状态码:

$response->assertFound();

assertGone

断言响应具有 “已消失” (410) HTTP 状态码:

$response->assertGone();

assertHeader

断言响应中存在给定的头部和相应值:

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

assertHeaderMissing

断言响应中不包含给定的头部:

$response->assertHeaderMissing($headerName);

assertInternalServerError

断言响应具有 “内部服务器错误” (500) HTTP 状态码:

$response->assertInternalServerError();

assertJson

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

$response->assertJson(array $data, $strict = false);

assertJsonCount

断言响应的 JSON 在给定的键下具有预期数量的项:

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

assertJsonFragment

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

Route::get('/users', function () {
    return [
        'users' => [
            [
                'name' => 'Taylor Otwell',
            ],
        ],
    ];
});

$response->assertJsonFragment(['name' => 'Taylor Otwell']);

assertJsonIsArray

断言响应的 JSON 是一个数组:

$response->assertJsonIsArray();

assertJsonIsObject

断言响应的 JSON 是一个对象:

$response->assertJsonIsObject();

assertJsonMissing

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

$response->assertJsonMissing(array $data);

assertJsonMissingExact

断言响应不包含精确的 JSON 数据:

$response->assertJsonMissingExact(array $data);

assertJsonMissingValidationErrors

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

$response->assertJsonMissingValidationErrors($keys);

更通用的 assertValid 方法可以用来断言响应没有返回 JSON 验证错误,并且没有错误被闪存到会话存储中。

assertJsonPath

断言响应在指定的路径下包含给定的数据:

$response->assertJsonPath($path, $expectedValue);

例如,如果应用程序返回以下 JSON 响应:

{
    "user": {
        "name": "Steve Schoger"
    }
}

您可以这样断言用户对象的名称属性与给定的值匹配:

$response->assertJsonPath('user.name', 'Steve Schoger');

assertJsonMissingPath

断言响应不包含给定的路径:

$response->assertJsonMissingPath($path);

例如,如果应用程序返回以下 JSON 响应:

{
    "user": {
        "name": "Steve Schoger"
    }
}

您可以这样断言它不包含 user 对象的 email 属性:

$response->assertJsonMissingPath('user.email');

assertJsonStructure

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

$response->assertJsonStructure(array $structure);

例如,如果应用程序返回的 JSON 响应包含以下数据:

{
    "user": {
        "name": "Steve Schoger"
    }
}

您可以这样断言 JSON 结构符合您的预期:

$response->assertJsonStructure([
    'user' => [
        'name',
    ]
]);

有时,应用程序返回的 JSON 响应可能包含对象数组:

{
    "user": [
        {
            "name": "Steve Schoger",
            "age": 55,
            "location": "Earth"
        },
        {
            "name": "Mary Schoger",
            "age": 60,
            "location": "Earth"
        }
    ]
}

在这种情况下,您可以使用 * 字符来断言数组中所有对象的结构:

$response->assertJsonStructure([
    'user' => [
        '*' => [
             'name',
             'age',
             'location'
        ]
    ]
]);

assertJsonValidationErrors

断言响应包含给定键的 JSON 验证错误。此方法应在断言响应时使用,其中验证错误作为 JSON 结构返回,而不是被闪存到会话中:

$response->assertJsonValidationErrors(array $data, $responseKey = 'errors');

更通用的 assertInvalid 方法可以用来断言响应返回了 JSON 验证错误,或者错误被闪存到会话存储中。

assertJsonValidationErrorFor

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

$response->assertJsonValidationErrorFor(string $key, $responseKey = 'errors');

assertMethodNotAllowed

断言响应具有方法不被允许 (405) HTTP 状态码:

$response->assertMethodNotAllowed();

assertMovedPermanently

断言响应具有永久移动 (301) HTTP 状态码:

$response->assertMovedPermanently();

assertLocation

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

$response->assertLocation($uri);

assertContent

断言给定的字符串与响应内容匹配:

$response->assertContent($value);

assertNoContent

断言响应具有给定的 HTTP 状态码且没有内容:

$response->assertNoContent($status = 204);

assertStreamedContent

断言给定的字符串与流式响应内容匹配:

$response->assertStreamedContent($value);

assertNotFound

断言响应具有 “未找到” (404) HTTP 状态码:

$response->assertNotFound();

assertOk

断言响应具有 200 HTTP 状态码:

$response->assertOk();

assertPaymentRequired

断言响应具有 “需要支付” (402) HTTP 状态码:

$response->assertPaymentRequired();

assertPlainCookie

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

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

assertRedirect

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

$response->assertRedirect($uri = null);

assertRedirectContains

断言响应是否重定向到包含给定字符串的 URI:

$response->assertRedirectContains($string);

assertRedirectToRoute

断言响应是重定向到给定的命名路由:

$response->assertRedirectToRoute($name, $parameters = []);

assertRedirectToSignedRoute

断言响应是重定向到给定的签名路由:

$response->assertRedirectToSignedRoute($name = null, $parameters = []);

assertRequestTimeout

断言响应具有请求超时 (408) HTTP 状态码:

$response->assertRequestTimeout();

assertSee

断言给定的字符串包含在响应中。除非你传递第二个参数为 false,否则此断言会自动转义给定的字符串:

$response->assertSee($value, $escaped = true);

assertSeeInOrder

断言给定的字符串按顺序包含在响应中。除非你传递第二个参数为 false,否则此断言会自动转义给定的字符串:

$response->assertSeeInOrder($values, $escaped = true);

assertSeeText

断言给定的文本包含在响应中。除非你传递第二个参数为 false,否则此断言会自动转义给定的字符串。此方法会将响应内容传递给 strip_tags PHP 函数,然后再进行断言:

$response->assertSeeText($value, $escaped = true);

assertSuccessful

断言响应具有成功的 HTTP 状态码(200-299):

$response->assertSuccessful();

assertUnauthorized

断言响应具有 “未授权” (401) HTTP 状态码:

$response->assertUnauthorized();

assertUnprocessable

断言响应具有 “不可处理” (422) HTTP 状态码:

$response->assertUnprocessable();

assertNoContent

断言响应没有内容,返回 HTTP 状态码 204 或 205:

$response->assertNoContent($status = 204);

认证断言

Laravel 还提供了各种与认证相关的断言,您可以在应用程序的功能测试中使用这些断言。请注意,这些方法是直接在测试类上调用的,而不是在由 getpost 等方法返回的 Illuminate\Testing\TestResponse 实例上调用。

assertAuthenticated

断言用户已认证:

$this->assertAuthenticated($guard = null);

assertGuest

断言用户未认证:

$this->assertGuest($guard = null);

assertAuthenticatedAs

断言某个特定用户已认证:

$this->assertAuthenticatedAs($user, $guard = null);

验证断言

Laravel 提供了两种主要的与验证相关的断言,您可以使用它们来确保请求中提供的数据是有效的或无效的。

assertValid

断言响应中没有给定键的验证错误。此方法可以用于断言响应中包含的验证错误是作为 JSON 结构返回的,或者验证错误已被刷新到会话中:

// 断言没有验证错误...
$response->assertValid();

// 断言给定的键没有验证错误...
$response->assertValid(['name', 'email']);

assertInvalid

断言响应中有给定键的验证错误。此方法可以用于断言响应中包含的验证错误是作为 JSON 结构返回的,或者验证错误已被刷新到会话中:

$response->assertInvalid(['name', 'email']);

您还可以断言给定的键有特定的验证错误消息。当这样做时,您可以提供整个消息或仅提供消息的一部分:

$response->assertInvalid([
    'name' => 'The name field is required.',
    'email' => 'valid email address',
]);