HTTP 功能测试

功能测试用于查看应用程序单次调用的执行结果,涵盖返回单个 Web 表单结果、访问 API 接口等场景。此功能非常实用,支持测试单个请求的完整生命周期,从而确保路由正常工作、响应格式正确,并可对执行结果进行分析。

测试类

进行功能测试时,所有测试类均须使用 CodeIgniter\Test\DatabaseTestTraitCodeIgniter\Test\FeatureTestTrait。鉴于这些测试工具依赖正确的数据库初始化,若在类中重写了相关方法,务必确保调用 parent::setUp()parent::tearDown()

<?php

namespace Tests\Feature;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
use CodeIgniter\Test\FeatureTestTrait;

class FooTest extends CIUnitTestCase
{
    use DatabaseTestTrait;
    use FeatureTestTrait;

    protected function setUp(): void
    {
        parent::setUp();

        $this->myClassMethod();
    }

    protected function tearDown(): void
    {
        parent::tearDown();

        $this->anotherClassMethod();
    }
}

请求页面

功能测试本质上就是调用应用上的某个接口并返回结果。为此,可使用 call() 方法。

  1. 第一个参数是要使用的 HTTP 方法(最常用的是 GETPOST)。

  2. 第二个参数是要测试的站点 URI 路径。

  3. 第三个参数 $params 接受一个数组,用于填充所使用的 HTTP 方法对应的超全局 变量。因此,GET 方法会填充 $_GET 变量,而 POST 请求则会填充 $_POST 数组。$params 也可用于 格式化请求

    备注

    $params 数组并不适用于所有 HTTP 方法,但为保持一致性而保留。

// Get a simple page
$result = $this->call('GET', '/');

// Submit a form
$result = $this->call('post', 'contact', [
    'name'  => 'Fred Flintstone',
    'email' => 'flintyfred@example.com',
]);

快捷方法

为每个 HTTP 方法提供了快捷方法,以简化输入并使意图更清晰:

$this->get($path, $params);
$this->post($path, $params);
$this->put($path, $params);
$this->patch($path, $params);
$this->delete($path, $params);
$this->options($path, $params);

设置不同路由

可以通过将路由数组传递给 withRoutes() 方法来使用自定义路由集合,该方法会覆盖 系统中任何现有的路由:

$routes = [
    ['GET', 'users', 'UserController::list'],
];

$result = $this->withRoutes($routes)->get('users');

每个「路由」是一个包含 3 个元素的数组,包含 HTTP 方法(或使用 “add” 表示所有)、 要匹配的 URI 以及路由目标。

设置 Session 值

可以使用 withSession() 方法在单个测试期间设置自定义 Session 值。该方法接受一个关联数组, 这些值在发出请求时会存在于 $_SESSION 变量中;也可传入 null, 表示使用 $_SESSION 的当前值。这对于测试认证等场景很有用。

$values = [
    'logged_in' => 123,
];

$result = $this->withSession($values)->get('admin');

// Or...

$_SESSION['logged_in'] = 123;

$result = $this->withSession()->get('admin');

跳过事件

事件在应用中很有用,但在测试期间可能会带来问题。尤其是用于发送邮件的事件。可以 使用 skipEvents() 方法告诉系统跳过任何事件处理:

$result = $this->skipEvents()->post('users', $userInfo);

格式化请求

使用 withBodyFormat() 方法可设置请求体格式,目前支持 jsonxml。 在测试 JSON 或 XML API 时,此功能可按控制器预期的格式构造请求。

该方法会自动将传给 call()post()get() 等方法的参数,按指定格式转换并填入请求体。

同时自动设置相应的 Content-Type 标头。

// If your feature test contains this:
$result = $this->withBodyFormat('json')->post('users', $userInfo);

// Your controller can then get the parameters passed in with:
$userInfo = $this->request->getJson();

设置请求体

可以使用 withBody() 方法设置请求体,可按需自行格式化请求体。 如果要测试更复杂的 XML,推荐使用此方法。

该方法不会自动设置 Content-Type 标头。如果需要,可以使用 withHeaders() 方法设置。

检查响应

FeatureTestTrait::call() 返回一个 TestResponse 实例。有关如何在测试用例中 使用此类执行额外断言和验证,请参阅 测试响应