yii2控制器单元测试应使用functional模块,它启动轻量级应用实例以支持完整请求生命周期,需配合yii2-codeception扩展及正确配置config/test.php。

Yii2控制器单元测试该用哪个模块
Yii2项目里写控制器测试,别直接上 unit 模块——它不加载应用上下文,$this->action、Yii::$app 全是 null。得用 functional 模块,它启动轻量级应用实例,能模拟真实请求生命周期。
-
functional依赖yii2-codeception扩展,需确认已安装并配置了config/test.php - 不要混用
unit和functional测试类,命名和引导方式不同(比如FunctionalTestervsUnitTester) - 若只测逻辑不涉路由或 session,可考虑手动构造
Controller实例 + mockModule,但多数场景不如functional稳定
怎么写一个能跑通的 action 测试用例
核心是让 Codeception 发起一次“伪 HTTP 请求”,触发控制器 action 并检查响应。不是调用方法那么简单。
- 用
$I->amOnPage('/site/index')或$I->sendAjaxPostRequest('/site/login', [...])触发 action - 路由必须匹配实际配置,比如
urlManager开启了美化,就得用/site/index,不能写index.php?r=site%2Findex - 响应断言优先用
$I->seeResponseCodeIs(200)和$I->see('Welcome'),避免直接读$I->grabResponse()解析 HTML - 若 action 重定向,用
$I->seeCurrentUrlEquals('/site/success'),别指望$I->canSeeResponseContainsJson()
<?php class SiteControllerCest
{
public function testIndexAction(FunctionalTester $I)
{
$I->amOnPage('/site/index');
$I->seeResponseCodeIs(200);
$I->see('Home');
}
}
测试带参数或 POST 数据的 action 容易错在哪
常见错误是把参数塞进 URL 当 GET,但实际 action 用 $request->post() 取值,导致空数组、验证失败或 400 错误。
- GET 参数走
$I->amOnPage('/post/view?id=123');POST/JSON 数据必须用$I->sendAjaxPostRequest()或$I->submitForm() -
submitForm()会自动设置Content-Type: application/x-www-form-urlencoded,适合表单;传 JSON 请用sendAjaxPostRequest()并手动设 header - 注意 CSRF:默认开启时,
submitForm()会自动抓取隐藏字段,但sendAjaxPostRequest()不会——要么关掉测试环境的enableCsrfValidation,要么提前$I->grabCSRF()补进去
为什么测试里 Yii::$app->user->isGuest 总是 true
因为 functional 测试默认不登录用户,所有 session、auth 都是干净状态。这不是 bug,是设计使然。
- 登录用户要用
$I->amLoggedInAs($user)(需先定义User模型或 ID) -
amLoggedInAs()底层调用Yii::$app->user->login(),并持久化 session ID,后续请求自动携带 - 如果 action 依赖特定角色或权限,得提前在测试前赋予:
$user->role = 'admin'; $I->amLoggedInAs($user) - 别在测试中手动改
Yii::$app->user->identity,它不会同步到 session,下次请求仍为 guest
测试控制器最麻烦的从来不是写断言,而是搞清“这个请求到底经过了哪些中间件、是否进了 beforeAction、session 是不是被 reset 过”。每次跑不通,先看日志里有没有 Invalid CSRF token 或 Session not started —— 这些比逻辑错误更常卡住人。











