HTTP 测试
简介
Laravel 为向应用发起 HTTP 请求并检查输出提供了非常流畅的 API。例如,看一个如下定义的测试:
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
方法在请求发送给应用前自定义请求头。可以在请求中添加任何要自定义的请求头:
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 中间件会自动禁用。
会话/认证
Laravel 提供了几个辅助函数在 HTTP 测试时处理会话。首先,可以使用 withSession
方法将会话数据设置为给定数组。这在向应用发送请求前在会话中添加数据时很有用:
class ExampleTest extends TestCase
{
public function testApplication()
{
$response = $this->withSession(['foo' => 'bar'])
->get('/');
}
}
当然,会话一个常见的用法是维护认证用户的状态。actingAs
辅助方法提供了一个简单的方法将给定用户认证为当前用户。例如,我们可以使用 模型工厂 生成并授权用户:
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
,get
,post
,put
,patch
和 delete
方法可用于发起各种类型的 HTTP 请求。还可以在这些方法中轻松传递数据和请求头。首先,我们编写一个测试,向 /user
发起一个 POST
请求并断言期望返回的数据:
class ExampleTest extends TestCase
{
/**
* 一个基本功能的测试示例
*
* @return void
*/
public function testBasicExample()
{
$response = $this->json('POST', '/user', ['name' => 'Sally']);
$response
->assertStatus(201)
->assertJson([
'created' => true,
]);
}
}
assertJson
方法将响应转换为数组,并使用PHPUnit::assertArraySubset
验证给定数组存在于应用返回的 JSON 响应中。因此,如果 JSON 响应中还有其它属性,只要给定属性片段存在测试仍会通过。
验证 JSON 完全匹配
如果要验证给定数组和应用返回的 JSON 完全 匹配,可以使用 assertExactJson
方法:
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
方法极大的简化了文件上传测试。例如,我们可以结合这两个功能轻松测试头像上传表单:
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
方法创建文件时,可以指定图片的宽、高和大小来更好地测试验证规则:
UploadedFile::fake()->image('avatar.jpg', $width, $height)->size(100);
除了创建图片,还可以使用 create
方法创建任何其它类型的文件:
UploadedFile::fake()->create('document.pdf', $sizeInKilobytes);
可用的断言方法
断言响应
Laravel 为 PHPUnit 测试提供了各种自定义断言方法。这些断言可以在 json
,get
,post
,put
和 delete
测试方法返回的响应上使用:
assertCookie
assertCookieExpired
assertCookieNotExpired
assertCookieMissing
assertDontSee
assertDontSeeText
assertExactJson
assertForbidden
assertHeader
assertHeaderMissing
assertJson
assertJsonCount
assertJsonFragment
assertJsonMissing
assertJsonMissingExact
assertJsonStructure
assertJsonValidationErrors
assertLocation
assertNotFound
assertOk
assertPlainCookie
assertRedirect
assertSee
assertSeeInOrder
assertSeeText
assertSeeTextInOrder
assertSessionHas
assertSessionHasAll
assertSessionHasErrors
assertSessionHasErrorsIn
assertSessionHasNoErrors
assertSessionMissing
assertStatus
assertSuccessful
assertViewHas
assertViewHasAll
assertViewIs
assertViewMissing
assertCookie
断言响应包含给定 Cookie:
$response->assertCookie($cookieName, $value = null);
assertCookieExpired
断言响应包含给定 Cookie 并且过期了:
$response->assertCookieExpired($cookieName);
assertCookieNotExpired
断言响应包含给定 Cookie 但没有过期:
$response->assertCookieNotExpired($cookieName);
assertCookieMissing
断言响应不包含给定 Cookie:
$response->assertCookieMissing($cookieName);
assertDontSee
断言给定字符串不包含在响应中:
$response->assertDontSee($value);
assertDontSeeText
断言给定字符串不包含在响应文本中:
$response->assertDontSeeText($value);
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);
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);
assertJsonStructure
断言响应有给定的 JSON 结构:
$response->assertJsonStructure(array $structure);
assertJsonValidationErrors
断言响应有给定键的 JSON 验证错误:
$response->assertJsonValidationErrors($keys);
assertLocation
断言响应在 Location
响应头中有给定 URL 值:
$response->assertLocation($uri);
assertNotFound
断言响应有 404 状态码:
$response->assertNotFound();
assertOk
断言响应有 200 状态码:
$response->assertOk();
assertPlainCookie
断言响应包含给定 Cookie(未加密):
$response->assertPlainCookie($cookieName, $value = null);
assertRedirect
断言响应重定向到给定 URI:
$response->assertRedirect($uri);
assertSee
断言给定字符串包含在响应中:
$response->assertSee($value);
assertSeeInOrder
断言给定字符串按顺序包含在响应中:
$response->assertSeeInOrder(array $values);
assertSeeText
断言给定字符串包含在响应文本中:
$response->assertSeeText($value);
assertSeeTextInOrder
断言给定字符串按顺序包含在给定响应文本中:
$response->assertSeeTextInOrder(array $values);
assertSessionHas
断言会话包含给定数据:
$response->assertSessionHas($key, $value = null);
assertSessionHasAll
断言会话有给定列表的值:
$response->assertSessionHasAll(array $data);
assertSessionHasErrors
断言会话包含给定字段的错误:
$response->assertSessionHasErrors(array $keys, $format = null, $errorBag = 'default');
assertSessionHasErrorsIn
断言会话有给定错误:
$response->assertSessionHasErrorsIn($errorBag, $keys = [], $format = null);
assertSessionHasNoErrors
断言会话没有错误:
$response->assertSessionHasNoErrors();
assertSessionMissing
断言会话不包含给定键:
$response->assertSessionMissing($key);
assertStatus
断言响应有给定状态码:
$response->assertStatus($code);
assertSuccessful
断言响应有成功的状态码:
$response->assertSuccessful();
assertViewHas
断言响应视图是给定的数据:
$response->assertViewHas($key, $value = null);
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); |
断言给定凭证是无效的 |