yii持续集成核心是测试环境可复现与变更触发链不中断:需容器化隔离、对齐codeception.yml与test.php路径、显式启用yii2/yii3模块并配置正确configfile,否则ci中yii::$app为null。

Yii 框架的持续集成(CI)不是配个 phpunit 就完事,核心在于「测试环境可复现」和「代码变更触发链不中断」。没做容器化隔离、没拆清测试数据生命周期、没把 codeception.yml 和 tests/_config/test.php 对齐真实应用启动路径,CI 流水线跑通了也白搭——它可能在本地能过,在 CI 环境里连 Yii::$app 都是 null。
CI 流水线里 codeception run 报 Class not found 或 Application not bootstrapped
根本原因是 Codeception 启动时找不到 Yii 应用上下文,不是 PHP 自动加载错了,而是配置路径或模块启用方式不对。
- Yii 2 项目必须在
tests/unit.suite.yml中显式启用Yii2模块,并确保configFile指向一个能返回完整yii\web\Application实例的文件(通常是tests/_config/test.php),而不是直接 require 入口脚本 - Yii 3 项目改用
Yii3模块,configFile必须是 DI 容器可加载的配置(如config/test/web.php),不能沿用 Yii 2 的test.php入口写法 -
codeception.yml中的paths: tests:必须是真实存在的目录路径,比如tests/,不是tests/unit/;否则 suite 加载失败,模块根本不会初始化 - 删掉
tests/_bootstrap.php里所有手动require或includeYii 自动加载器的代码——Yii2/Yii3模块已接管,重复加载会触发Cannot redeclare class
数据库在 CI 中每次运行都残留旧数据或连接失败
单元测试(unit)默认不走数据库,functional/acceptance 才真正连接 DB;但即使启用了,没管好连接生命周期,CI 就会随机失败。
- 测试数据库必须独立于开发库,且在每次 suite 启动前清空:用
truncate表或事务回滚(推荐后者,快且干净),别依赖 shell 脚本手动DROP DATABASE -
config/test/db.php必须返回有效的yii\db\Connection实例,且用户名/密码/主机需适配 CI 环境(例如 Docker 内网地址mysql而非localhost) - functional 测试中若用
$I->seeRecord()或$I->grabRecord(),要确认该测试套件已启用Db模块,并在_bootstrap.php或 suite 配置中正确设置了populate: true和cleanup: true - 别在 unit 测试里硬连 DB——用
Stub::make(User::class, ['id' => 1])或Mockery::mock(User::class)替代,否则 CI 容器里 MySQL 服务未就绪时直接超时
Acceptance 测试在 CI 中打开浏览器就卡死或 400 错误
Acceptance 不是功能验证工具,它是端到端链路探针;CI 环境缺 ChromeDriver、CSRF 没关、URL 规则没适配,它就只能白屏。
- CI 容器必须预装
chromium-browser+chromedriver(版本严格匹配),并用--headless --no-sandbox --disable-dev-shm-usage启动 -
tests/_config/test.php的request组件必须设'enableCsrfValidation' => false,否则表单提交永远返回 400 -
urlManager配置里hostInfo要设为测试域名(如http://yii-test.local),不能留空或写localhost;否则$I->amOnPage('/login')生成的 URL 是错的 - AssetBundle 发布路径在 CI 中常 404,建议在测试配置中临时关闭压缩:
'assetManager' => ['forceCopy' => true],避免 symlink 权限问题
Jenkins/GitLab CI 中部署 Yii 应用前的镜像构建关键点
Docker 镜像不是越小越好,而是“最小可运行+可调试”。线上镜像删掉 composer 和 dev 依赖是对的,但 CI 构建阶段必须保留调试能力。
- Dockerfile 用多阶段构建:build 阶段装
composer、跑composer install --no-dev;final 阶段只 COPYvendor/和代码,不带源码和锁文件 -
.dockerignore必须排除tests/、.git/、composer.lock(如果 final 阶段不用)、node_modules/,否则镜像体积暴涨且含敏感信息 - K8S Deployment 的
livenessProbe别直接 ping/health,改用 Yii 内置命令:exec: ["sh", "-c", "php yii health/check"],避免 Web 层未就绪却误判存活 - CI 流水线最后一步不是
docker push,而是用kubectl apply -f k8s/deployment.yaml并加--record,方便后续回滚时看到谁推的哪个 commit
最常被跳过的环节是:没在 CI 中验证 config/test/*.php 是否语法合法,也没跑 php -l 扫描所有测试文件。一个 if ($a = $b) 写成赋值,测试全绿,上线就炸——这种错误只有在 CI 的 PHP 解析阶段才能暴露。











