Laravel HTTP 测试

简介

Laravel 为生成 HTTP 请求、测试输出提供了流式 API。举个例子,我们来看看 Laravel 自带的测试示例:

<?php
​
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->get('/');
        $response->assertStatus(200);
    }
}

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

自定义请求头

我们可以通过 withHeaders 方法在请求发送给应用之前自定义请求头。你可以添加任意自定义请求头到请求实例:

<?php

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

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

注:运行测试时,CSRF 中间件会自动被禁止。

cookies

我们可以在请求之前使用withCookiewithCookies方法设置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('/');
    }
}

对响应进行调试

向应用发起测试请求后,dumpdumpHeadersdumpSession 方法可用于检查和调试响应内容:

<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $response = $this->get('/');
        $response->dumpHeaders();
        $response->dumpSession();
        $response->dump();
    }
}

会话/认证

Laravel 提供了多个辅助函数用于在 HTTP 测试期间处理会话(Session),首先,我们可以使用 withSession 方法来设置会话数据。这对于在发起请求之前加载会话数据很有用:

<?php
class ExampleTest extends TestCase
{
    public function testApplication()
    {
        $response = $this->withSession(['foo' => 'bar'])
                         ->get('/');
    }
}

当然,会话最常见的用途还是维护认证用户的状态。对此,辅助函数 actionAs 方法提供了一个简单的方式来认证当前用户,例如,我们可以使用模型工厂来生成并认证用户:

<?php
use App\User;
class ExampleTest extends TestCase
{
    public function testApplication()
    {
        $user = factory(User::class)->create();
        $response = $this->actingAs($user)
                         ->withSession(['foo' => 'bar'])
                         ->get('/');
    }
}

我们还可以通过传递 guard 名作为 actionAs 方法的第二个参数来指定使用哪一个 guard 来认证给定用户:

$this->actingAs($user, 'api');

测试 JSON API

Laravel 还提供了多个辅助函数用于测试 JSON API 及其响应。例如,jsongetJsonpostJsonputJsonpatchJsondeleteJsonoptionJson 方法用于通过多种 HTTP 请求方式发出请求。我们还可以轻松传递数据和请求头到这些方法。作为开始,我们编写测试来生成 POST 请求到 /user 并断言返回的数据是否是我们所期望的:

<?php

class ExampleTest extends TestCase
{
    /**
     * A basic functional test example.
     *
     * @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
{
    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->postJson('/user', ['name' => '学院君']);
        $response
            ->assertStatus(201)
            ->assertExactJson([
                'created' => true,
            ]);
    }
}

验证 JSON 路径

如果想要验证 JSON 响应是否在指定路径上包含某些数据,可以使用 assertJsonPath 方法:

<?php
​
class ExampleTest extends TestCase
{
    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
        $response = $this->postJson('/user', ['name' => '学院君']);
​
        $response
            ->assertStatus(201)
            ->assertJsonPath('team.owner.name', 'foo')
    }
}

测试文件上传

Illuminate\Http\UploadedFile 类提供了一个 fake 方法用于生成假文件或图片进行测试。这一机制和 Storage Facade 的 fake 方法联合在一起,极大地简化了文件上传的测试。例如,可以联合这两个特性来轻松测试头像上传表单:

<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
    public function testAvatarUpload()
    {
        Storage::fake('avatars');
        $response = $this->json('POST', '/avatar', [
            'avatar' => UploadedFile::fake()->image('avatar.jpg')
        ]);
        // Assert the file was stored...
        Storage::disk('avatars')->assertExists('avatar.jpg');
        // Assert a file does not exist...
        Storage::disk('avatars')->assertMissing('missing.jpg');
    }
}

伪造文件自定义

使用 fake 方法创建文件的时候,可以指定宽度、高度、以及图片的尺寸以便更好的测试验证规则:

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

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

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

如果需要的话,可以传递 $mimeType 参数到 create 方法来显式定义该文件应应该返回的 MIME 类型:

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

有效的断言方法

响应断言

Laravel 为 PHPUnit 测试提供了多个自定义的断言方法。这些断言可以通过测试方法 jsongetpostputdelete 返回的响应进行访问:

assertCookie
assertCookieExpired
assertCookieNotExpired
assertCookieMissing
assertCreated
assertDontSee
assertDontSeeText
assertExactJson
assertForbidden
assertHeader
assertHeaderMissing
assertJson
assertJsonCount
assertJsonFragment
assertJsonMissing
assertJsonMissingExact
assertJsonMissingValidationErrors
assertJsonPath
assertJsonStructure
assertJsonValidationErrors
assertLocation
assertNoContent
assertNotFound
assertOk
assertPlainCookie
assertRedirect
assertSee
assertSeeInOrder
assertSeeText
assertSeeTextInOrder
assertSessionHas
assertSessionHasInput
assertSessionHasAll
assertSessionHasErrors
assertSessionHasErrorsIn
assertSessionHasNoErrors
assertSessionDoesntHaveErrors
assertSessionMissing
assertStatus
assertSuccessful
assertUnauthorized
assertViewHas
assertViewHasAll
assertViewIs
assertViewMissing

认证断言

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); 断言给定认证信息无效

查看笔记

扫码一下
查看教程更方便