laravel
9. 测试
HTTP 测试

介绍

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

<?php
 
test('应用程序返回成功响应', function () {
    $response = $this->get('/');
 
    $response->assertStatus(200);
});
<?php
 
namespace Tests\Feature;
 
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    /**
     * 一个基本的测试示例。
     */
    public function test_应用程序返回成功响应(): void
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

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

发送请求

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

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

<?php
 
test('基本请求', function () {
    $response = $this->get('/');
 
    $response->assertStatus(200);
});
<?php
 
namespace Tests\Feature;
 
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    /**
     * 一个基本的测试示例。
     */
    public function test_一个基本请求(): void
    {
        $response = $this->get('/');
 
        $response->assertStatus(200);
    }
}

一般来说,您的每个测试应该只向您的应用程序发出一个请求。如果在单个测试方法中执行多个请求,可能会出现意外行为。

[!注意]
为了方便起见,在运行测试时,CSRF 中间件会自动禁用。

自定义请求头

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

<?php
 
test('与头交互', 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
{
    /**
     * 一个基本的功能测试示例。
     */
    public function test_与头交互(): void
    {
        $response = $this->withHeaders([
            'X-Header' => 'Value',
        ])->post('/user', ['name' => 'Sally']);
 
        $response->assertStatus(201);
    }
}

Cookie

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

<?php
 
test('与 Cookie 交互', 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_与_Cookie_交互(): void
    {
        $response = $this->withCookie('color', 'blue')->get('/');
 
        $response = $this->withCookies([
            'color' => 'blue',
            'name' => 'Taylor',
        ])->get('/');
 
        //
    }
}

会话/认证

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

<?php
 
test('与会话交互', function () {
    $response = $this->withSession(['banned' => false])->get('/');
 
    //
});
<?php
 
namespace Tests\Feature;
 
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    public function test_与会话交互(): void
    {
        $response = $this->withSession(['banned' => false])->get('/');
 
        //
    }
}

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

<?php
 
use App\Models\User;
 
test('需要认证的操作', 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_需要认证的操作(): void
    {
        $user = User::factory()->create();
 
        $response = $this->actingAs($user)
                         ->withSession(['banned' => false])
                         ->get('/');
 
        //
    }
}

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

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

调试响应

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

<?php
 
test('基本测试', function () {
    $response = $this->get('/');
 
    $response->dumpHeaders();
 
    $response->dumpSession();
 
    $response->dump();
});
<?php
 
namespace Tests\Feature;
 
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    /**
     * 一个基本的测试示例。
     */
    public function test_基本测试(): void
    {
        $response = $this->get('/');
 
        $response->dumpHeaders();
 
        $response->dumpSession();
 
        $response->dump();
    }
}

或者,您可以使用ddddHeadersddSession方法来转储有关响应的信息,然后停止执行:

<?php
 
test('基本测试', function () {
    $response = $this->get('/');
 
    $response->ddHeaders();
 
    $response->ddSession();
 
    $response->dd();
});
<?php
 
namespace Tests\Feature;
 
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    /**
     * 一个基本的测试示例。
     */
    public function test_基本测试(): void
    {
        $response = $this->get('/');
 
        $response->ddHeaders();
 
        $response->ddSession();
 
        $response->dd();
    }
}

异常处理

有时您可能需要测试您的应用程序是否抛出特定的异常。要实现这一点,您可以通过Exceptions外观“伪造”异常处理程序。一旦异常处理程序被伪造,您可以使用assertReportedassertNotReported方法对请求期间抛出的异常进行断言:

<?php
 
use App\Exceptions\InvalidOrderException;
use Illuminate\Support\Facades\Exceptions;
 
test('异常被抛出', function () {
    Exceptions::fake();
 
    $response = $this->get('/order/1');
 
    // 断言抛出了异常...
    Exceptions::assertReported(InvalidOrderException::class);
 
    // 对异常进行断言...
    Exceptions::assertReported(function (InvalidOrderException $e) {
        return $e->getMessage() === '订单无效。';
    });
});
<?php
 
namespace Tests\Feature;
 
use App\Exceptions\InvalidOrderException;
use Illuminate\Support\Facades\Exceptions;
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    /**
     * 一个基本的测试示例。
     */
    public function test_异常被抛出(): void
    {
        Exceptions::fake();
 
        $response = $this->get('/');
 
        // 断言抛出了异常...
        Exceptions::assertReported(InvalidOrderException::class);
 
        // 对异常进行断言...
        Exceptions::assertReported(function (InvalidOrderException $e) {
            return $e->getMessage() === '订单无效。';
        });
    }
}

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 数据:

<?php
 
test('发出 API 请求', 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
{
    /**
     * 一个基本的功能测试示例。
     */
    public function test_发出_API_请求(): void
    {
        $response = $this->postJson('/api/user', ['name' => 'Sally']);
 
        $response
            ->assertStatus(201)
            ->assertJson([
                'created' => true,
            ]);
    }
}

此外,JSON 响应数据可以作为响应上的数组变量进行访问,这使得您可以方便地检查 JSON 响应中返回的各个值:

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

[!注意]
assertJson方法将响应转换为数组,以验证应用程序返回的 JSON 响应中存在给定的数组。因此,如果 JSON 响应中还有其他属性,只要给定的片段存在,此测试仍将通过。

断言精确的 JSON 匹配

如前所述,assertJson方法可用于断言 JSON 响应中存在一段 JSON。如果您想验证给定的数组精确匹配您的应用程序返回的 JSON,您应该使用assertExactJson方法:

<?php
 
test('断言精确的 JSON 匹配', function () {
    $response = $this->postJson('/user', ['name' => 'Sally']);
 
    $response
        ->assertStatus(201)
        ->assertExactJson([
            'created' => true,
        ]);
});
 
<?php
 
namespace Tests\Feature;
 
use Tests\TestCase;
 
class ExampleTest extends TestCase
{
    /**
     * 一个基本的功能测试示例。
     */
    public function test_断言精确的_JSON_匹配(): void
    {
        $response = $this->postJson('/user', ['name' => 'Sally']);
 
        $response
            ->assertStatus(201)
            ->assertExactJson([
                'created' => true,
            ]);
    }
}

对 JSON 路径进行断言

如果您想验证 JSON 响应在指定路径包含给定的数据,您应该使用assertJsonPath方法:

<?php
 
test('断言 JSON 路径值', 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
{
    /**
     * 一个基本的功能测试示例。
     */
    public function test_断言_JSON_路径值(): 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 中缺少特定的属性:

use Illuminate\Testing\Fluent\AssertableJson;
 
test('流畅的 JSON', function () {
    $response = $this->getJson('/users/1');
 
    $response
        ->assertJson(fn (AssertableJson $json) =>
            $json->where('id', 1)
                 ->where('name', 'Victoria Faith')
                 ->where('email
#### 理解 `etc` 方法
 
在上述示例中,您可能已经注意到我们在断言链的末尾调用了 `etc` 方法。此方法告知 Laravel,JSON 对象上可能存在其他属性。如果未使用 `etc` 方法,并且 JSON 对象上存在您未进行断言的其他属性,则测试将失败。
 
这种行为的目的是通过强制您要么对属性明确进行断言,要么通过 `etc` 方法明确允许其他属性,从而保护您不会在 JSON 响应中无意地暴露敏感信息。
 
但是,您应该注意,在断言链中不包含 `etc` 方法并不能确保不会向嵌套在 JSON 对象中的数组添加其他属性。`etc` 方法仅确保在调用 `etc` 方法的嵌套级别上不存在其他属性。
 
#### 断言属性的存在/不存在
 
要断言属性是否存在,您可以使用 `has` 和 `missing` 方法:
 
```php
$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()
             )
    );

但是,您可以不必对 users 集合进行两次单独的 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 方法,极大地简化了文件上传的测试。例如,您可以结合这两个功能轻松测试头像上传表单:

<?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 方法。view 方法接受视图名称和一个可选的数据数组。该方法返回一个 Illuminate\Testing\TestView 实例,该实例提供了几个方法,可方便地对视图的内容进行断言:

<?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

断言响应具有错误请求(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

断言响应是一个“下载”。通常,这意味着

assertJson

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

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

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

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);

assertJson MissingExact

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

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

assertJson MissingValidationErrors

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

$response->assertJson MissingValidationErrors($keys);

[!NOTE]
更通用的 assertValid 方法可用于断言响应中没有作为 JSON 返回的验证错误并且没有错误闪存在会话存储中。

assertJsonPath

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

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

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

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

您可以这样断言 user 对象的 name 属性与给定值匹配:

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

assertJson MissingPath

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

$response->assertJson MissingPath($path);

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

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

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

$response->assertJson MissingPath('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');

[!NOTE]
更通用的 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(array $values, $escaped = true);

assertSeeText

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

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

assertSeeTextInOrder

断言给定的字符串按顺序包含在响应文本中。除非您将第二个参数传递为 false,否则此断言将自动转义给定的字符串。在进行断言之前,响应内容将传递给 strip_tags PHP 函数:

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

assertServerError

断言响应具有服务器错误(>= 500 , < 600)HTTP 状态码:

$response->assertServerError();

assertServiceUnavailable

断言响应具有“服务不可用”(503)HTTP 状态码:

$response->assertServiceUnavailable();

assertSessionHas

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

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

如果需要,可以将闭包作为 assertSessionHas 方法的第二个参数提供。如果闭包返回 true,则断言将通过:

$response->assertSessionHas($key, function (User $value) {
    return $value->name === 'Taylor Otwell';
});

assertSessionHasInput

断言会话在闪存输入数组中具有给定的值:

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

如果需要,可以将闭包作为 assertSessionHasInput 方法的第二个参数提供。如果闭包返回 true,则断言将通过:

use Illuminate\Support\Facades\Crypt;

$response->assertSessionHasInput($key, function (string $value) {
    return Crypt::decryptString($value) === 'secret';
});

assertSessionHasAll

断言会话包含给定的键/值对数组:

$response->assertSessionHasAll(array $data);

例如,如果您的应用程序的会话包含 namestatus 键,您可以这样断言两者都存在并具有指定的值:

$response->assertSessionHasAll([
    'name' => 'Taylor Otwell',
    'status' => 'active',
]);

assertSessionHasErrors

断言会话对于给定的 $keys 包含错误。如果 $keys 是关联数组,则断言会话对于每个字段(键)包含特定的错误消息(值)。当测试将验证错误闪存在会话中而不是作为 JSON 结构返回的路由时,应使用此方法:

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

例如,要断言 nameemail 字段的验证错误消息已闪存在会话中,您可以这样调用 assertSessionHasErrors 方法:

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

或者,您可以断言给定字段具有特定的验证错误消息:

$response->assertSessionHasErrors([
    'name' => 'The given name was invalid.'
]);

[!NOTE]
更通用的 assertInvalid 方法可用于断言响应具有作为 JSON 返回的验证错误错误闪存在会话存储中。

assertSessionHasErrorsIn

断言会话在特定的错误包中对于给定的 $keys 包含错误。如果 $keys 是关联数组,则断言会话在错误包中对于每个字段(键)包含特定的错误消息(值):

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

assertSessionHasNoErrors

断言会话没有验证错误:

$response->assertSessionHasNoErrors();

assertSessionDoesntHaveErrors

断言会话对于给定的键没有验证错误:

$response->assertSessionDoesntHaveErrors($keys = [], $format = null, $errorBag = 'default');

[!NOTE]
更通用的 assertValid 方法可用于断言响应中没有作为 JSON 返回的验证错误并且没有错误闪存在会话存储中。

assertSession Missing

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

$response->assertSession Missing($key);

assertStatus

断言响应具有给定的 HTTP 状态码:

$response->assertStatus($code);

assertSuccessful

断言响应具有成功的(>= 200 且 < 300)HTTP 状态码:

$response->assertSuccessful();

assertTooManyRequests

断言响应具有过多请求(429)HTTP 状态码:

$response->assertTooManyRequests();

assertUnauthorized

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

$response->assertUnauthorized();

assertUnprocessable

断言响应具有无法处理的实体(422)HTTP 状态码:

$response->assertUnprocessable();

assertUnsupportedMediaType

断言响应具有不支持的媒体类型(415)HTTP 状态码:

$response->assertUnsupportedMediaType();

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',
]);

assertViewHas

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

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

将闭包作为 assertViewHas 方法的第二个参数传递将允许您检查并对特定的视图数据进行断言:

$response->assertViewHas('user', function (User $user) {
    return $user->name === 'Taylor';
});

此外,视图数据可以作为响应上的数组变量进行访问,以便您方便地进行检查:

expect($response['name'])->toBe('Taylor');
$this->assertEquals('Taylor', $response['name']);

assertViewHasAll

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

$response->assertViewHasAll(array $data);

此方法可用于断言视图仅包含与给定键匹配的数据:

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

或者,您可以断言视图数据存在且具有特定值:

$response->assertViewHasAll([
    'name' => 'Taylor Otwell',
    'email' => 'taylor@example.com,',
]);

assertViewIs

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

$response->assertViewIs($value);

assertView Missing

断言给定的数据键未提供给应用程序响应中返回的视图:

$response->assertView Missing($key);

认证断言

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',
]);