为Yii2上传组件编写单元测试需覆盖文件类型、大小、扩展名、路径安全及错误提示,初始化Codeception环境并配置test模式,模型中启用skipOnEmpty=false,验证规则须同时指定extensions和mimeTypes,上传路径须用baseName+extension防止遍历,测试需构造UploadedFile实例并断言getFirstError。

为 Yii2 上传组件编写单元测试,必须覆盖文件类型校验、大小限制、扩展名白名单、上传路径安全及错误提示逻辑,避免因绕过验证导致恶意文件写入服务器。
初始化 Codeception 测试环境
在项目根目录执行 ./vendor/bin/codecept bootstrap,自动生成 tests/ 目录结构和默认配置文件。
编辑 tests/_bootstrap.php,确保加载了 Yii2 测试环境配置:需定义 YII_ENV = 'test',并引入 config/test.php 而非 web.php 或 main.php;否则上传模型中依赖的组件(如 Yii::$app->security)将不可用。
运行 ./vendor/bin/codecept build 生成测试执行器类,这一步失败会导致后续所有测试无法注入 $I 实例。
创建上传模型与验证规则
在 models/UploadForm.php 中定义上传模型,关键字段必须声明为 public $imageFile; 并使用 UploadedFile::getInstance() 获取实例。
rules() 中必须显式启用 'skipOnEmpty' => false,否则空文件上传时验证直接跳过,无法触发 file 验证器的扩展名或大小检查。
添加以下验证规则:
① 文件类型限制:['imageFile', 'file', 'extensions' => 'png,jpg,gif', 'mimeTypes' => 'image/png,image/jpeg,image/gif'];【仅靠 extensions 不足以防 MIME 欺骗,必须配 mimeTypes】
② 大小限制:['imageFile', 'file', 'maxSize' => 2097152](2MB),单位是字节,不是 KB 或 MB 字符串。
③ 安全路径处理:upload() 方法中禁止拼接用户传入的原始文件名,必须用 $file->baseName . '.' . $file->extension,否则可能触发路径遍历(如 ../../../etc/passwd)。
编写上传模型单元测试
方法一:使用 Codeception Unit 模块验证模型规则
在 tests/unit/models/UploadFormTest.php 中创建测试类,继承 Codeception\Test\Unit。
测试空文件上传:$model->imageFile = null; $this->assertFalse($model->validate(['imageFile']));,验证是否返回 false 并设置 error。
测试非法扩展名:$model->imageFile = new UploadedFile(['name' => 'shell.php', 'type' => 'application/x-php']); $this->assertFalse($model->validate());,注意不能只测 name,必须构造真实 UploadedFile 实例。
方法二:模拟上传流并断言错误信息
手动构造一个伪造的 $_FILES 数组,调用 UploadedFile::getInstanceByName('imageFile'),再赋值给模型属性;然后调用 $model->validate(),最后用 $this->assertContains('Only files with these extensions are allowed', $model->getFirstError('imageFile')) 断言提示文案。
【不要用 echo 或 var_dump 查看错误,必须用 getFirstError() 获取模型级验证消息】
功能测试:模拟真实表单提交
在 tests/functional/models/UploadFormCest.php 中编写功能测试,继承 Codeception\Test\Unit,方法名以 test 开头。
第一步:访问上传页面,确认表单存在:$I->amOnPage('/site/upload'); $I->seeElement('form'); $I->seeElement('input[type="file"]');
第二步:提交空文件,检查重定向后是否仍停留在原页并显示错误:$I->submitForm('form', []); $I->seeCurrentUrlEquals('/site/upload'); $I->see('Only files with these extensions are allowed');
第三步:上传合法 PNG 文件(需提前准备 tests/_data/test.png):$I->attachFile('input[type="file"]', 'test.png'); $I->click('Submit'); $I->seeCurrentUrlEquals('/site/success');
第四步:验证文件是否真实写入指定目录且无 PHP 扩展:$I->seeFileFound('test.png', 'uploads/'); $I->dontSeeFileFound('test.php', 'uploads/');
第五步:手动清理上传文件,防止污染后续测试:unlink(codecept_output_dir() . '/uploads/test.png');


















