HTTP 测试
介绍
Laravel 提供了一种非常流畅的 API,用于向应用程序发出 HTTP 请求并检查输出。例如,请查看下面定义的功能测试:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* 一个基本的测试示例。
*
* @return void
*/
public function testBasicTest()
{
$response = $this->get('/');
$response->assertStatus(200);
}
}
get
方法向应用程序发出 GET
请求,而 assertStatus
方法断言返回的响应应具有给定的 HTTP 状态码。除了这个简单的断言,Laravel 还包含多种断言,用于检查响应头、内容、JSON 结构等。
自定义请求头
您可以使用 withHeaders
方法在请求发送到应用程序之前自定义请求的头。这允许您向请求添加任何自定义头:
<?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,
]);
}
}
在运行测试时,CSRF 中间件会自动禁用。
Cookies
您可以使用 withCookie
或 withCookies
方法在发出请求之前设置 cookie 值。withCookie
方法接受 cookie 名称和值作为其两个参数,而 withCookies
方法接受一个名称/值对的数组:
<?php
class ExampleTest extends TestCase
{
public function testCookies()
{
$response = $this->withCookie('color', 'blue')->get('/');
$response = $this->withCookies([
'color' => 'blue',
'name' => 'Taylor',
])->get('/');
}
}
调试响应
在向应用程序发出测试请求后,可以使用 dump
、dumpHeaders
和 dumpSession
方法检查和调试响应内容:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class ExampleTest extends TestCase
{
/**
* 一个基本的测试示例。
*
* @return void
*/
public function testBasicTest()
{
$response = $this->get('/');
$response->dumpHeaders();
$response->dumpSession();
$response->dump();
}
}
会话 / 认证
Laravel 提供了几个助手,用于在 HTTP 测试期间处理会话。首先,您可以使用 withSession
方法将会话数据设置为给定数组。这对于在向应用程序发出请求之前加载会话数据非常有用:
<?php
class ExampleTest extends TestCase
{
public function testApplication()
{
$response = $this->withSession(['foo' => 'bar'])
->get('/');
}
}
会话的一个常见用途是维护已认证用户的状态。actingAs
助手方法提供了一种简单的方法来将给定用户认证为当前用户。例如,我们可以使用 模型工厂 来生成和认证用户:
<?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
方法来指定应使用哪个守卫来认证给定用户:
$this->actingAs($user, 'api')
测试 JSON API
Laravel 还提供了几个助手,用于测试 JSON API 及其响应。例如,可以使用 json
、getJson
、postJson
、putJson
、patchJson
、deleteJson
和 optionsJson
方法发出带有各种 HTTP 动词的 JSON 请求。您还可以轻松地将数据和头传递给这些方法。首先,让我们编写一个测试,以向 /user
发出 POST
请求并断言返回了预期的数据:
<?php
class ExampleTest extends TestCase
{
/**
* 一个基本的功能测试示例。
*
* @return void
*/
public function testBasicExample()
{
$response = $this->postJson('/user', ['name' => 'Sally']);
$response
->assertStatus(201)
->assertJson([
'created' => true,
]);
}
}
assertJson
方法将响应转换为数组,并利用 PHPUnit::assertArraySubset
验证给定数组是否存在于应用程序返回的 JSON 响应中。因此,如果 JSON 响应中有其他属性,只要给定的片段存在,此测试仍将通过。
此外,JSON 响应数据可以作为响应上的数组变量访问:
$this->assertTrue($response['created']);
验证精确的 JSON 匹配
如果您想验证给定数组是否与应用程序返回的 JSON 完全匹配,则应使用 assertExactJson
方法:
<?php
class ExampleTest extends TestCase
{
/**
* 一个基本的功能测试示例。
*
* @return void
*/
public function testBasicExample()
{
$response = $this->json('POST', '/user', ['name' => 'Sally']);
$response
->assertStatus(201)
->assertExactJson([
'created' => true,
]);
}
}
验证 JSON 路径
如果您想验证 JSON 响应在指定路径中包含某些给定数据,则应使用 assertJsonPath
方法:
<?php
class ExampleTest extends TestCase
{
/**
* 一个基本的功能测试示例。
*
* @return void
*/
public function testBasicExample()
{
$response = $this->json('POST', '/user', ['name' => 'Sally']);
$response
->assertStatus(201)
->assertJsonPath('team.owner.name', 'foo')
}
}
测试文件上传
Illuminate\Http\UploadedFile
类提供了一个 fake
方法,可用于生成用于测试的虚拟文件或图像。这与 Storage
facade 的 fake
方法结合使用,大大简化了文件上传的测试。例如,您可以结合这两个功能轻松测试头像上传表单:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
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
方法创建文件时,您可以指定图像的宽度、高度和大小,以便更好地测试您的验证规则:
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 为您的 PHPUnit 功能测试提供了多种自定义断言方法。这些断言可以在从 json
、get
、post
、put
和 delete
测试方法返回的响应上访问:
assertCookieassertCookieExpiredassertCookieNotExpiredassertCookieMissingassertCreatedassertDontSeeassertDontSeeTextassertExactJsonassertForbiddenassertHeaderassertHeaderMissingassertJsonassertJsonCountassertJsonFragmentassertJsonMissingassertJsonMissingExactassertJsonMissingValidationErrorsassertJsonPathassertJsonStructureassertJsonValidationErrorsassertLocationassertNoContentassertNotFoundassertOkassertPlainCookieassertRedirectassertSeeassertSeeInOrderassertSeeTextassertSeeTextInOrderassertSessionHasassertSessionHasInputassertSessionHasAllassertSessionHasErrorsassertSessionHasErrorsInassertSessionHasNoErrorsassertSessionDoesntHaveErrorsassertSessionMissingassertStatusassertSuccessfulassertUnauthorizedassertViewHasassertViewHasAllassertViewIsassertViewMissing
assertCookie
断言响应包含给定的 cookie:
$response->assertCookie($cookieName, $value = null);
assertCookieExpired
断言响应包含给定的 cookie 并且已过期:
$response->assertCookieExpired($cookieName);
assertCookieNotExpired
断言响应包含给定的 cookie 并且未过期:
$response->assertCookieNotExpired($cookieName);
assertCookieMissing
断言响应不包含给定的 cookie:
$response->assertCookieMissing($cookieName);
assertCreated
断言响应具有 201 状态码:
$response->assertCreated();
assertDontSee
断言给定字符串不包含在响应中。此断言将自动转义给定字符串,除非您传递第二个参数 false
:
$response->assertDontSee($value, $escaped = true);
assertDontSeeText
断言给定字符串不包含在响应文本中。此断言将自动转义给定字符串,除非您传递第二个参数 false
:
$response->assertDontSeeText($value, $escaped = true);
assertExactJson
断言响应包含给定 JSON 数据的精确匹配:
$response->assertExactJson(array $data);
assertForbidden
断言响应具有禁止(403)状态码:
$response->assertForbidden();
assertHeader
断言响应上存在给定的头:
$response->assertHeader($headerName, $value = null);
assertHeaderMissing
断言响应上不存在给定的头:
$response->assertHeaderMissing($headerName);
assertJson
断言响应包含给定的 JSON 数据:
$response->assertJson(array $data, $strict = false);
assertJsonCount
断言响应 JSON 在给定键处具有预期数量的项目:
$response->assertJsonCount($count, $key = null);
assertJsonFragment
断言响应包含给定的 JSON 片段:
$response->assertJsonFragment(array $data);
assertJsonMissing
断言响应不包含给定的 JSON 片段:
$response->assertJsonMissing(array $data);
assertJsonMissingExact
断言响应不包含精确的 JSON 片段:
$response->assertJsonMissingExact(array $data);
assertJsonMissingValidationErrors
断言响应没有给定键的 JSON 验证错误:
$response->assertJsonMissingValidationErrors($keys);
assertJsonPath
断言响应在指定路径中包含给定数据:
$response->assertJsonPath($path, array $data, $strict = false);
assertJsonStructure
断言响应具有给定的 JSON 结构:
$response->assertJsonStructure(array $structure);
assertJsonValidationErrors
断言响应具有给定的 JSON 验证错误:
$response->assertJsonValidationErrors(array $data);
assertLocation
断言响应在 Location
头中具有给定的 URI 值:
$response->assertLocation($uri);
assertNoContent
断言响应具有给定的状态码且无内容:
$response->assertNoContent($status = 204);
assertNotFound
断言响应具有未找到的状态码:
$response->assertNotFound();
assertOk
断言响应具有 200 状态码:
$response->assertOk();
assertPlainCookie
断言响应包含给定的 cookie(未加密):
$response->assertPlainCookie($cookieName, $value = null);
assertRedirect
断言响应是重定向到给定 URI:
$response->assertRedirect($uri);
assertSee
断言给定字符串包含在响应中。此断言将自动转义给定字符串,除非您传递第二个参数 false
:
$response->assertSee($value, $escaped = true);
assertSeeInOrder
断言给定字符串按顺序包含在响应中。此断言将自动转义给定字符串,除非您传递第二个参数 false
:
$response->assertSeeInOrder(array $values, $escaped = true);
assertSeeText
断言给定字符串包含在响应文本中。此断言将自动转义给定字符串,除非您传递第二个参数 false
:
$response->assertSeeText($value, $escaped = true);
assertSeeTextInOrder
断言给定字符串按顺序包含在响应文本中。此断言将自动转义给定字符串,除非您传递第二个参数 false
:
$response->assertSeeTextInOrder(array $values, $escaped = true);
assertSessionHas
断言会话包含给定的数据:
$response->assertSessionHas($key, $value = null);
assertSessionHasInput
断言会话在闪存输入数组中具有给定值:
$response->assertSessionHasInput($key, $value = null);
assertSessionHasAll
断言会话具有给定的值列表:
$response->assertSessionHasAll(array $data);
assertSessionHasErrors
断言会话包含给定 $keys
的错误。如果 $keys
是关联数组,则断言会话包含每个字段(键)的特定错误消息(值):
$response->assertSessionHasErrors(array $keys, $format = null, $errorBag = 'default');
assertSessionHasErrorsIn
断言会话在特定错误包中包含给定 $keys
的错误。如果 $keys
是关联数组,则断言会话在错误包中包含每个字段(键)的特定错误消息(值):
$response->assertSessionHasErrorsIn($errorBag, $keys = [], $format = null);
assertSessionHasNoErrors
断言会话没有错误:
$response->assertSessionHasNoErrors();
assertSessionDoesntHaveErrors
断言会话没有给定键的错误:
$response->assertSessionDoesntHaveErrors($keys = [], $format = null, $errorBag = 'default');
assertSessionMissing
断言会话不包含给定键:
$response->assertSessionMissing($key);
assertStatus
断言响应具有给定代码:
$response->assertStatus($code);
assertSuccessful
断言响应具有成功(>= 200 且 < 300)状态码:
$response->assertSuccessful();
assertUnauthorized
断言响应具有未授权(401)状态码:
$response->assertUnauthorized();
assertViewHas
断言响应视图被赋予了一块数据:
$response->assertViewHas($key, $value = null);
此外,视图数据可以作为响应上的数组变量访问:
$this->assertEquals('Taylor', $response['name']);
assertViewHasAll
断言响应视图具有给定的数据列表:
$response->assertViewHasAll(array $data);
assertViewIs
断言给定视图由路由返回:
$response->assertViewIs($value);
assertViewMissing
断言响应视图缺少一块绑定数据:
$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); | 断言给定凭据无效。 |