codeigniter自带unit_test类不能替代phpunit,因其无测试生命周期、不支持mock/隔离/ci集成,且输出混入http流;应使用官方phpunit测试套件及ci_testcase基类,它自动配置路径、预加载核心类并提供request()等模拟方法。

CodeIgniter 自带的 unit_test 类不是 PHPUnit,它是一个轻量级、内建的断言工具,适合快速验证控制器逻辑、辅助函数或简单业务规则——但不能替代真正的单元测试框架。如果你看到文档里写“加载 $this->load->library('unit_test')”,那只是个结果展示器,不是可 mock、可隔离、可集成 CI 的测试方案。
为什么不能靠 unit_test 类做真正单元测试
这个类本质是“运行即输出”,没有测试生命周期(setup/teardown),不支持断言失败中断、不生成标准测试报告、无法跳过或分组执行,更不能模拟 $this->input 或 $this->db 等依赖:
- 调用
$this->unit->run()后立刻 echo 输出,混在 HTTP 响应流里,不适合 CLI 运行或 CI 流水线 - 所有测试共享同一个
$this->unit实例,状态无法重置,多次运行可能污染结果 - 不支持数据提供器(
dataProvider)、不兼容expectException()等现代断言能力 - 预期结果只能是字符串匹配或固定类型名(如
'is_string'),无法校验对象结构、数组键值对、异常消息细节
应该用 PHPUnit + CI_TestCase 替代
CodeIgniter 官方测试套件(tests/ 目录)早已基于 PHPUnit 构建,并提供了 CI_TestCase 基类,它做了三件事:
- 自动设置
BASEPATH、APPPATH和虚拟文件系统(vfsStream) - 预加载核心类和辅助函数,避免“Class not found”错误
- 封装了
get_instance()模拟、reset_instance()清理、request()模拟 HTTP 请求等实用方法
示例:测试一个只返回硬编码数组的模型方法
class UserModelTest extends CI_TestCase
{
public function test_get_all_returns_array()
{
$model = new UserModel();
$result = $model->get_all();
$this->assertIsArray($result);
$this->assertNotEmpty($result);
}
}
注意:你必须确保 tests/Bootstrap.php 已正确加载,且 phpunit.xml 中 bootstrap 指向它——否则 CI_TestCase 会因常量未定义而直接 fatal error。
控制器测试必须绕过路由和输入解析
直接 new 一个控制器无法触发 CodeIgniter 的生命周期(如 _remap、钩子、安全过滤)。正确做法是使用 CI_TestCase::request() 方法发起模拟请求:
-
$this->request('GET', ['MyController', 'index'])→ 调用MyController::index() -
$this->request('POST', 'api/users', ['name' => 'foo'])→ POST 到api/users,参数进$this->input->post() - 返回值是控制器输出内容(
echo或$this->output->get_output()),不是响应对象
陷阱:若控制器依赖 $this->rest->key(RestServer 场景),需提前在测试中手动注入或 patch $this->rest 属性,request() 不会自动初始化第三方库。
RestServer API 测试要分层,别全塞进一个 test
针对 chriskacerguis/restserver 的测试,建议拆成三层:
- 单元层:单独测试认证类(如
ApiKeyAuth)的check()方法,mock$this->rest和$this->db - 控制器层:用
request()测试路由是否命中、HTTP 状态码是否正确(如 401)、响应格式是否为 JSON - 端到端层:启动内置 PHP server(
php -S)或用 Guzzle 发真实 HTTP 请求,验证跨域、Content-Type、认证头透传等
最容易被忽略的是:RestServer 的 $config['auth_override_class_method'] 配置在测试环境默认不生效——因为 Bootstrap.php 通常没加载 rest.php 配置文件,得手动 $this->config->load('rest') 并覆盖 key。











