TP6 彻底移除 think\testing\TestCase,改用 PHPUnit\Framework\TestCase;需手动初始化应用、用 Http::get/post 模拟请求,响应断言用 getCode();测试库须独立并手动迁移;Facade 需容器先注册。

ThinkPHP 6 升级后 TestCase 类找不到或报错
TP6 彻底移除了 TP5.x 的 think\testing\TestCase,改用 PHPUnit 原生方式组织测试,不再提供框架封装的基类。直接沿用旧写法会触发 Class 'think\testing\TestCase' not found。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 删除所有继承自
think\testing\TestCase的测试类,改用PHPUnit\Framework\TestCase - 手动加载应用环境:在
setUp()中调用App::beforeStart()或显式初始化容器(如需模拟 HTTP 请求,推荐用think\facade\Http的invoke) - 数据库测试前务必清空/重置测试库,TP6 不再自动隔离测试数据库连接
- 注意
phpunit.xml中的bootstrap路径要指向 TP6 的tests/bootstrap.php(若你按标准结构生成过),否则Facade和服务无法自动注册
TP6 中如何正确模拟请求并断言响应
旧版 $this->get()、$this->post() 等快捷方法已失效,TP6 不再注入这些方法到测试类中。强行调用会报 Call to undefined method。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
think\facade\Http构造请求:Http::withHeaders(['Accept' => 'application/json'])->post('/api/user', ['name' => 'test']) - 响应对象是
think\Response实例,断言状态码用$response->getCode(),不要用$response->getStatusCode()(那是 PSR-7 接口,TP6 响应不实现它) - JSON 响应体需先调用
$response->getContent()再json_decode(),直接$response->json()不存在 - 若需完整模拟中间件链(如鉴权、日志),别跳过
App::make('http'),否则中间件不执行
数据迁移 + 测试数据库隔离失败的常见原因
TP6 默认不为每个测试用例重置数据库,phpunit --colors tests/ 连续跑多次,很可能因上一个测试残留数据导致下一个失败。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 禁用生产配置中的
'deploy' => true(若开启,迁移命令会跳过 SQL 执行) - 在
setUp()中执行Artisan::call('migrate:refresh', ['--seed' => true]),但必须确保测试数据库是独立库(如database_test),不能和开发库共用 - 使用
think\migration\Migrator时,注意setConnection()必须早于run(),否则仍操作默认连接 - SQLite 内存数据库(
:memory:)虽快,但 TP6 的迁移器对它支持不稳定,容易报SQLSTATE[HY000]: General error,建议用独立 MySQL 测试库
Facade 在测试中未解析或静态调用失败
TP6 的 Facade 是延迟绑定的,若测试中直接写 Cache::get('key') 却没触发容器注册,就会报 Call to undefined method think\Facade\Cache::get()。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 确保
tests/bootstrap.php中已执行require __DIR__.'/../vendor/autoload.php';和App::initCommon(); - 在测试方法里,先调用
App::getContainer()->get('cache')一次,强制 Facade 初始化;或直接用app('cache')替代Cache::get() - 避免在
setUpBeforeClass()中大量使用 Facade——该方法运行时容器可能尚未完全就绪 - 检查
config/app.php中的'providers'是否包含think\Service\ServiceProvider,漏掉会导致部分 Facade 绑定失败
TP6 的测试体系更贴近原生 PHPUnit,但也意味着很多“开箱即用”的便利没了。最容易被忽略的是容器生命周期和数据库连接复用问题——同一个 TestCase 类里的多个方法共享一个连接实例,不手动 close() 就可能遇到事务残留或锁表。


















