Webman单元测试跑不起来主因是tests/bootstrap.php未正确加载框架上下文,必须显式引入support/bootstrap.php并初始化配置、容器与时区,控制器测试需用Request::create()构造请求并手动注入mock依赖,数据库等外部服务必须mock。

Webman 单元测试跑不起来,90% 是因为 tests/bootstrap.php 没配对 —— 不是 PHPUnit 装错了,也不是测试类写法有问题,而是框架上下文根本没加载。
为什么 app() 报错或 Container 为空
直接运行 phpunit 时只加载了 vendor/autoload.php,support/bootstrap.php 完全没执行。结果就是 app()、config()、db() 全部不可用,报 Call to undefined function app() 或 Attempt to access property "xxx" on null。
- 必须在
tests/bootstrap.php开头显式require __DIR__ . '/../support/bootstrap.php'(注意:要放在autoload.php之后) - 别信“只要 autoload 就够了”的直觉——Webman 不像 Laravel 那样自动桥接测试环境
- 如果项目用了自定义配置路径,还要补一句
Config::load(__DIR__ . '/../config/'),否则route.php、container.php读不到 - 手动设时区:
date_default_timezone_set(config('app.timezone', 'Asia/Shanghai')),否则 Carbon 实例或日志时间错乱
测试控制器时怎么避免 404 Not Found 或 $this->request is null</H3>
<p>不要 <code>new UserController()
后直接调 show(),也不要用 file_get_contents('http://localhost/...') 发真实请求——前者缺 Request 和依赖注入,后者是集成测试,慢且不稳定。
- 用
Webman\Http\Request::create('/user/123', 'GET') 构造请求对象,它自带完整上下文(query、header、method 等)
- 若控制器构造函数依赖
UserService,先 mock:$mockService = $this->createMock(UserService::class),再 new UserController($mockService)
- 跳过路由匹配层,直调方法:
$result = $controller->show($request, '123')
- 所有中间件、日志、监控等生产级组件,在测试中应禁用:在
config/middleware.php 测试配置里返回空数组,或只保留 SessionMiddleware 这类必要项
哪些依赖必须 Mock,不 Mock 会怎样
Webman\Http\Request::create('/user/123', 'GET') 构造请求对象,它自带完整上下文(query、header、method 等)UserService,先 mock:$mockService = $this->createMock(UserService::class),再 new UserController($mockService)
$result = $controller->show($request, '123')
config/middleware.php 测试配置里返回空数组,或只保留 SessionMiddleware 这类必要项Mock,不 Mock 会怎样一跑测试就卡住、超时、抛 DatabaseConnectionException 或 RedisException,基本可以确定你没隔离外部服务。
立即学习“PHP免费学习笔记(深入)”;
- 数据库(
db()、Eloquent、Query Builder)必须 mock,用$this->createMock(Connection::class)或更轻量的Phake/Prophecy - Redis 客户端(
redis())、HTTP 客户端(GuzzleHttp\Client)、消息队列(amqp)全部要 mock,否则测试环境连不上就会 fail - 文件系统操作(
Storage::disk('local'))、第三方 API 调用(如微信支付 SDK)也得 mock,否则测试结果受网络、权限、配额影响 - mock 不是“假装它存在”,而是明确声明行为:
$mockService->method('find')->willReturn(null),让测试可预测、可重复
phpunit.xml 和 PhpStorm 配置里的硬坑
phpunit.xml 写错一行,bootstrap.php 就会被当成测试类反复加载,报 Cannot declare class Bootstrap;PhpStorm 的 Docker 映射多配一个路径,测试就找不到 bootstrap.php。
-
<directory></directory>值必须精确到测试类目录,比如tests/unit,不能写tests(否则会扫进tests/bootstrap.php) -
bootstrap属性值是相对路径,从phpunit.xml所在位置算起,正确写法是tests/bootstrap.php,不是./tests/bootstrap.php(多点)或tests/bootstrap.php(少 ./)——注意斜杠方向和层级 - PhpStorm 的 CLI Interpreter → Path mappings 中,
Remote path和Container path都不需要填,留空即可;填了反而导致路径解析失败 - 测试方法命名别用
testShow(),改用testShowUserReturns404WhenUserNotFound(),业务语义越强,后期排查越快
真正难的不是写断言,而是判断哪一层该被隔离、哪条路径该被覆盖。mock 多了测试变假,mock 少了又跑不动——边界感得靠每次失败的 DatabaseConnectionException 来校准。



















