HTTP 测试
简介
Laravel 提供了一个非常流畅的 API 用于向你的应用发起 HTTP 请求并检查响应。例如,请看下面定义的功能测试:
<?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
{
/**
* 一个基本的测试示例。
*/
public function test_the_application_returns_a_successful_response(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
}get 方法向应用发起 GET 请求,而 assertStatus 方法断言返回的响应应具有给定的 HTTP 状态码。除了这个简单的断言之外,Laravel 还包含各种用于检查响应头、内容、JSON 结构等的断言。
发起请求
要向你的应用发起请求,你可以在测试中调用 get、post、put、patch 或 delete 方法。这些方法不会真正向你的应用发起"真实"的 HTTP 请求。相反,整个网络请求是在内部模拟的。
测试请求方法返回的不是 Illuminate\Http\Response 实例,而是 Illuminate\Testing\TestResponse 实例,它提供了各种有用的断言方法,让你可以检查应用的响应:
<?php
test('basic request', function () {
$response = $this->get('/');
$response->assertStatus(200);
});<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* 一个基本的请求测试示例。
*/
public function test_a_basic_request(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
}一般来说,你的每个测试只应向你的应用发起一次请求。如果在单个测试方法中执行多个请求,可能会出现意外行为。
NOTE
为了方便,运行测试时 CSRF 中间件会自动禁用。
自定义请求头
你可以使用 withHeaders 方法在请求发送到应用之前自定义请求头。此方法允许你向请求添加任何自定义头:
<?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
{
/**
* 一个基本的函数式测试示例。
*/
public function test_interacting_with_headers(): void
{
$response = $this->withHeaders([
'X-Header' => 'Value',
])->post('/user', ['name' => 'Sally']);
$response->assertStatus(201);
}
}Cookie
你可以使用 withCookie 或 withCookies 方法在发起请求前设置 cookie 值。withCookie 方法接受 cookie 名称和值作为两个参数,而 withCookies 方法接受一个名称/值对数组:
<?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 方法将会话数据设置为给定的数组。这对于在向应用发起请求之前将会话加载数据非常有用:
<?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 辅助方法提供了一种简单的方法来将给定用户认证为当前用户。例如,我们可以使用模型工厂来生成并认证一个用户:
<?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');如果你想确保请求是未认证的,可以使用 actingAsGuest 方法:
$this->actingAsGuest();调试响应
向应用发起测试请求后,可以使用 dump、dumpHeaders 和 dumpSession 方法来检查和调试响应内容:
<?php
test('basic test', function () {
$response = $this->get('/');
$response->dump();
$response->dumpHeaders();
$response->dumpSession();
});<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* 一个基本的测试示例。
*/
public function test_basic_test(): void
{
$response = $this->get('/');
$response->dump();
$response->dumpHeaders();
$response->dumpSession();
}
}或者,你可以使用 dd、ddHeaders、ddBody、ddJson 和 ddSession 方法来转储响应信息然后停止执行:
<?php
test('basic test', function () {
$response = $this->get('/');
$response->dd();
$response->ddHeaders();
$response->ddBody();
$response->ddJson();
$response->ddSession();
});<?php
namespace Tests\Feature;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* 一个基本的测试示例。
*/
public function test_basic_test(): void
{
$response = $this->get('/');
$response->dd();
$response->ddHeaders();
$response->ddBody();
$response->ddJson();
$response->ddSession();
}
}异常处理
有时你可能需要测试你的应用是否抛出了特定的异常。为此,你可以通过 Exceptions 门面"伪造"异常处理器。一旦异常处理器被伪造,你就可以使用 assertReported 和 assertNotReported 方法对请求期间抛出的异常进行断言:
<?php
use App\Exceptions\InvalidOrderException;
use Illuminate\Support\Facades\Exceptions;
test('exception is thrown', function () {
Exceptions::fake();
$response = $this->get('/order/1');
// 断言抛出了异常...
Exceptions::assertReported(InvalidOrderException::class);
// 对异常进行断言...
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
{
/**
* 一个基本的测试示例。
*/
public function test_exception_is_thrown(): void
{
Exceptions::fake();
$response = $this->get('/');
// 断言抛出了异常...
Exceptions::assertReported(InvalidOrderException::class);
// 对异常进行断言...
Exceptions::assertReported(function (InvalidOrderException $e) {
return $e->getMessage() === 'The order was invalid.';
});
}
}assertNotReported 和 assertNothingReported 方法可用于断言请求期间未抛出给定的异常或未抛出任何异常:
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;
);assertDoesntThrow 方法可用于断言给定闭包内的代码没有抛出任何异常:
$this->assertDoesntThrow(fn () => (new ProcessOrder)->execute());测试 JSON API
Laravel 还提供了几个用于测试 JSON API 及其响应的辅助方法。例如,json、getJson、postJson、putJson、patchJson、deleteJson 和 optionsJson 方法可用于使用各种 HTTP 动词发起 JSON 请求。你还可以轻松地将数据和头传递给这些方法。让我们先编写一个测试,向 /api/user 发起 POST 请求,并断言返回了预期的 JSON 数据:
<?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
{
/**
* 一个基本的函数式测试示例。
*/
public function test_making_an_api_request(): void
{
$response = $this->postJson('/api/user', ['name' => 'Sally']);
$response
->assertStatus(201)
->assertJson([
'created' => true,
]);
}
}此外,JSON 响应数据可以作为响应上的数组变量访问,方便你检查 JSON 响应中返回的单个值:
expect($response['created'])->toBeTrue();$this->assertTrue($response['created']);NOTE
assertJson 方法将响应转换为数组,以验证给定的数组是否存在于应用返回的 JSON 响应中。因此,如果 JSON 响应中还有其他属性,只要给定的片段存在,此测试仍然会通过。
断言精确 JSON 匹配
如前所述,assertJson 方法可用于断言 JSON 片段存在于 JSON 响应中。如果你想验证给定的数组与应用返回的 JSON 完全匹配,则应使用 assertExactJson 方法:
<?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
{
/**
* 一个基本的函数式测试示例。
*/
public function test_asserting_an_exact_json_match(): void
{
$response = $this->postJson('/user', ['name' => 'Sally']);
$response
->assertStatus(201)
->assertExactJson([
'created' => true,
]);
}
}断言 JSON 路径
如果你希望验证 JSON 响应在指定路径包含给定数据,应使用 assertJsonPath 方法:
<?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
{
/**
* 一个基本的函数式测试示例。
*/
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 路径,可以使用 assertJsonPaths 方法。每个路径的预期值也可以是一个闭包:
$response->assertJsonPaths([
'team.owner.name' => 'Darian',
'team.owner.email' => fn (string $email) => str($email)->is('*@laravel.com'),
'team.members.0.name' => 'Sally',
]);你可以使用 assertJsonMissingPaths 方法来断言响应中缺少多个 JSON 路径:
$response->assertJsonMissingPaths([
'team.owner.password',
'team.members.0.api_token',
]);流畅的 JSON 测试
Laravel 还提供了一种优雅的方式来流畅地测试你的应用 JSON 响应。首先,向 assertJson 方法传递一个闭包。此闭包将接收一个 Illuminate\Testing\Fluent\AssertableJson 实例,可用于对你应用返回的 JSON 进行断言。where 方法可用于对 JSON 的特定属性进行断言,而 missing 方法可用于断言特定属性在 JSON 中不存在:
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;
/**
* 一个基本的函数式测试示例。
*/
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 对象上存在你未对其做过断言的任何其他属性时,测试将失败。
此行为背后的目的是通过强制你显式对属性进行断言或通过 etc 方法显式允许额外的属性,来保护你不会在 JSON 响应中意外暴露敏感信息。
但是,你应注意,在断言链中不包含 etc 方法并不能确保额外的属性不会添加到嵌套在 JSON 对象中的数组中。etc 方法仅确保在调用 etc 方法的嵌套级别上没有额外的属性。
断言属性存在 / 不存在
要断言属性存在或不存在,你可以使用 has 和 missing 方法:
$response->assertJson(fn (AssertableJson $json) =>
$json->has('data')
->missing('message')
);此外,hasAll 和 missingAll 方法允许同时断言多个属性的存在或不存在:
$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 集合中的每个项目进行相同的断言,可以使用 each 方法:
$response
->assertJson(fn (AssertableJson $json) =>
$json->has(3)
->each(fn (AssertableJson $json) =>
$json->whereType('id', 'integer')
->whereType('name', 'string')
->whereType('email', 'string')
->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 方法调用来断言 users 集合,不如进行一次调用,将闭包作为其第三个参数。这样做时,闭包将自动被调用并限定到集合中的第一个项目:
$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 类提供了 whereType 和 whereAllType 方法来实现这一点:
$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'])
);whereType 和 whereAllType 方法识别以下类型:string、integer、double、boolean、array 和 null。
测试文件上传
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 类提供以下断言方法:assertSee、assertSeeInOrder、assertSeeText、assertSeeTextInOrder、assertDontSee 和 assertDontSeeText。
如果需要,你可以通过将 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\Foundation\Testing\WithCachedRoutes trait 添加到你的测试用例中。在使用此 trait 的测试中,路由会被构建一次并存储在内存中,这意味着路由收集过程仅对所有测试运行一次:
<?php
use App\Http\Controllers\UserController;
use Illuminate\Foundation\Testing\WithCachedRoutes;
pest()->use(WithCachedRoutes::class);
test('basic example', function () {
$this->get(action([UserController::class, 'index']));
// ...
});<?php
namespace Tests\Feature;
use App\Http\Controllers\UserController;
use Illuminate\Foundation\Testing\WithCachedRoutes;
use Tests\TestCase;
class BasicTest extends TestCase
{
use WithCachedRoutes;
/**
* 一个基本的函数式测试示例。
*/
public function test_basic_example(): void
{
$response = $this->get(action([UserController::class, 'index']));
// ...
}
}可用的断言方法
响应断言
Laravel 的 Illuminate\Testing\TestResponse 类提供了各种自定义断言方法,你可以在测试应用时使用。这些断言可以在 json、get、post、put 和 delete 测试方法返回的响应上访问:
assertAcceptedassertBadRequestassertClientErrorassertConflictassertCookieassertCookieExpiredassertCookieNotExpiredassertCookieMissingassertCreatedassertDontSeeassertDontSeeTextassertDownloadassertExactJsonassertExactJsonStructureassertFailedDependencyassertForbiddenassertFoundassertGoneassertHeaderassertHeaderContainsassertHeaderMissingassertInternalServerErrorassertJsonassertJsonCountassertJsonFragmentassertJsonIsArrayassertJsonIsObjectassertJsonMissingassertJsonMissingExactassertJsonMissingValidationErrorsassertJsonPathassertJsonPathsassertJsonMissingPathassertJsonMissingPathsassertJsonStructureassertJsonValidationErrorsassertJsonValidationErrorForassertLocationassertMethodNotAllowedassertMovedPermanentlyassertContentassertNoContentassertStreamedassertStreamedContentassertNotFoundassertOkassertPaymentRequiredassertPlainCookieassertRedirectassertRedirectBackassertRedirectBackWithErrorsassertRedirectBackWithoutErrorsassertRedirectContainsassertRedirectToRouteassertRedirectToSignedRouteassertRequestTimeoutassertSeeassertSeeInOrderassertSeeTextassertSeeTextInOrderassertServerErrorassertServiceUnavailableassertSessionHasassertSessionHasInputassertSessionHasAllassertSessionHasErrorsassertSessionHasErrorsInassertSessionHasNoErrorsassertSessionDoesntHaveErrorsassertSessionMissingassertSessionMissingInputassertStatusassertSuccessfulassertTooManyRequestsassertUnauthorizedassertUnprocessableassertUnsupportedMediaTypeassertValidassertInvalidassertViewHasassertViewHasAllassertViewIsassertViewMissing
assertAccepted
断言响应具有 accepted(202)HTTP 状态码:
$response->assertAccepted();assertBadRequest
断言响应具有 bad request(400)HTTP 状态码:
$response->assertBadRequest();assertClientError
断言响应具有客户端错误(>= 400, < 500)HTTP 状态码:
$response->assertClientError();assertConflict
断言响应具有 conflict(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, $escape = true);assertDontSeeText
断言给定字符串不包含在响应文本中。除非传递 false 作为第二个参数,否则此断言会自动转义给定的字符串。在做出断言之前,此方法会将响应内容传递给 strip_tags PHP 函数:
$response->assertDontSeeText($value, $escape = true);assertDownload
断言响应是一个"下载"。通常,这意味着返回响应的调用路由返回了 Response::download 响应、BinaryFileResponse 或 Storage::download 响应:
$response->assertDownload();如果你愿意,可以断言可下载文件被分配了给定的文件名:
$response->assertDownload('image.jpg');assertExactJson
断言响应包含给定 JSON 数据的精确匹配:
$response->assertExactJson(array $data);assertExactJsonStructure
断言响应包含给定 JSON 结构的精确匹配:
$response->assertExactJsonStructure(array $data);此方法是 assertJsonStructure 的更严格变体。与 assertJsonStructure 相比,如果响应包含未在预期 JSON 结构中显式包含的任何键,此方法将失败。
assertFailedDependency
断言响应具有 failed dependency(424)HTTP 状态码:
$response->assertFailedDependency();assertForbidden
断言响应具有 forbidden(403)HTTP 状态码:
$response->assertForbidden();assertFound
断言响应具有 found(302)HTTP 状态码:
$response->assertFound();assertGone
断言响应具有 gone(410)HTTP 状态码:
$response->assertGone();assertHeader
断言给定的头和值存在于响应中:
$response->assertHeader($headerName, $value = null);assertHeaderContains
断言给定的头包含给定的子字符串值:
$response->assertHeaderContains($headerName, $value);assertHeaderMissing
断言给定的头不存在于响应中:
$response->assertHeaderMissing($headerName);assertInternalServerError
断言响应具有"Internal Server Error"(500)HTTP 状态码:
$response->assertInternalServerError();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);assertJsonMissingExact
断言响应不包含精确的 JSON 数据:
$response->assertJsonMissingExact(array $data);assertJsonMissingValidationErrors
断言响应在给定键上没有 JSON 验证错误:
$response->assertJsonMissingValidationErrors($keys);NOTE
更通用的 assertValid 方法可用于断言响应没有以 JSON 形式返回的验证错误,并且没有错误被闪存到会话存储中。
assertJsonPath
断言响应在指定路径包含给定的数据:
$response->assertJsonPath($path, $expectedValue);例如,如果你的应用返回以下 JSON 响应:
{
"user": {
"name": "Steve Schoger"
}
}你可以断言 user 对象的 name 属性与给定值匹配,如下所示:
$response->assertJsonPath('user.name', 'Steve Schoger');assertJsonPaths
断言响应在指定路径包含给定的数据:
$response->assertJsonPaths(array $paths);例如,你可以一次断言响应中的多个值:
$response->assertJsonPaths([
'user.name' => 'Steve Schoger',
'user.email' => fn (string $email) => str($email)->endsWith('@laravel.com'),
]);assertJsonMissingPath
断言响应不包含给定的路径:
$response->assertJsonMissingPath($path);例如,如果你的应用返回以下 JSON 响应:
{
"user": {
"name": "Steve Schoger"
}
}你可以断言它不包含 user 对象的 email 属性:
$response->assertJsonMissingPath('user.email');assertJsonMissingPaths
断言响应不包含给定的路径:
$response->assertJsonMissingPaths($paths);例如,你可以断言响应中缺少多个路径:
$response->assertJsonMissingPaths([
'user.email',
'user.password',
]);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
断言响应具有 method not allowed(405)HTTP 状态码:
$response->assertMethodNotAllowed();assertMovedPermanently
断言响应具有 moved permanently(301)HTTP 状态码:
$response->assertMovedPermanently();assertLocation
断言响应在 Location 头中具有给定的 URI 值:
$response->assertLocation($uri);assertContent
断言给定字符串与响应内容匹配:
$response->assertContent($value);assertNoContent
断言响应具有给定的 HTTP 状态码且没有内容:
$response->assertNoContent($status = 204);assertStreamed
断言响应是一个流式响应:
$response->assertStreamed();
assertStreamedContent
断言给定字符串与流式响应内容匹配:
$response->assertStreamedContent($value);assertNotFound
断言响应具有 not found(404)HTTP 状态码:
$response->assertNotFound();assertOk
断言响应具有 200 HTTP 状态码:
$response->assertOk();assertPaymentRequired
断言响应具有 payment required(402)HTTP 状态码:
$response->assertPaymentRequired();assertPlainCookie
断言响应包含给定的未加密 cookie:
$response->assertPlainCookie($cookieName, $value = null);assertRedirect
断言响应是重定向到给定的 URI:
$response->assertRedirect($uri = null);assertRedirectBack
断言响应是否重定向回上一页:
$response->assertRedirectBack();assertRedirectBackWithErrors
断言响应是否重定向回上一页并且会话具有给定的错误:
$response->assertRedirectBackWithErrors(
array $keys = [], $format = null, $errorBag = 'default'
);assertRedirectBackWithoutErrors
断言响应是否重定向回上一页并且会话不包含任何错误消息:
$response->assertRedirectBackWithoutErrors();assertRedirectContains
断言响应是否重定向到包含给定字符串的 URI:
$response->assertRedirectContains($string);assertRedirectToRoute
断言响应是重定向到给定的命名路由:
$response->assertRedirectToRoute($name, $parameters = []);assertRedirectToSignedRoute
断言响应是重定向到给定的签名路由:
$response->assertRedirectToSignedRoute($name = null, $parameters = []);assertRequestTimeout
断言响应具有 request timeout(408)HTTP 状态码:
$response->assertRequestTimeout();assertSee
断言给定字符串包含在响应中。除非传递 false 作为第二个参数,否则此断言会自动转义给定的字符串:
$response->assertSee($value, $escape = true);assertSeeInOrder
断言给定的字符串按顺序包含在响应中。除非传递 false 作为第二个参数,否则此断言会自动转义给定的字符串:
$response->assertSeeInOrder(array $values, $escape = true);assertSeeText
断言给定字符串包含在响应文本中。除非传递 false 作为第二个参数,否则此断言会自动转义给定的字符串。在做出断言之前,响应内容将传递给 strip_tags PHP 函数:
$response->assertSeeText($value, $escape = true);assertSeeTextInOrder
断言给定的字符串按顺序包含在响应文本中。除非传递 false 作为第二个参数,否则此断言会自动转义给定的字符串。在做出断言之前,响应内容将传递给 strip_tags PHP 函数:
$response->assertSeeTextInOrder(array $values, $escape = true);assertServerError
断言响应具有服务器错误(>= 500, < 600)HTTP 状态码:
$response->assertServerError();assertServiceUnavailable
断言响应具有"Service Unavailable"(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);例如,如果你的应用会话包含 name 和 status 键,你可以断言两者都存在并具有指定的值,如下所示:
$response->assertSessionHasAll([
'name' => 'Taylor Otwell',
'status' => 'active',
]);assertSessionHasErrors
断言会话包含给定 $keys 的错误。如果 $keys 是关联数组,则断言会话包含每个字段(键)的特定错误消息(值)。当测试将验证错误闪存到会话而不是以 JSON 结构返回的路由时,应使用此方法:
$response->assertSessionHasErrors(
array $keys = [], $format = null, $errorBag = 'default'
);例如,要断言 name 和 email 字段具有闪存到会话中的验证错误消息,你可以像这样调用 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 形式返回的验证错误,并且没有错误被闪存到会话存储中。
assertSessionMissing
断言会话不包含给定的键:
$response->assertSessionMissing($key);assertSessionMissingInput
断言会话在闪存输入数组中缺少给定的输入键:
$response->assertSessionMissingInput($key);assertStatus
断言响应具有给定的 HTTP 状态码:
$response->assertStatus($code);assertSuccessful
断言响应具有成功的(>= 200 且 < 300)HTTP 状态码:
$response->assertSuccessful();assertTooManyRequests
断言响应具有 too many requests(429)HTTP 状态码:
$response->assertTooManyRequests();assertUnauthorized
断言响应具有 unauthorized(401)HTTP 状态码:
$response->assertUnauthorized();assertUnprocessable
断言响应具有 unprocessable entity(422)HTTP 状态码:
$response->assertUnprocessable();assertUnsupportedMediaType
断言响应具有 unsupported media type(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',
]);如果你希望断言给定字段是唯一具有验证错误的字段,可以使用 assertOnlyInvalid 方法:
$response->assertOnlyInvalid(['name', 'email']);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);assertViewMissing
断言给定的数据键在应用响应中返回的视图上不可用:
$response->assertViewMissing($key);认证断言
Laravel 还提供了各种认证相关的断言,你可以在应用的功能测试中使用。请注意,这些方法是在测试类本身上调用的,而不是在 get 和 post 等方法返回的 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',
]);