httptestcase 需正确继承、启用协程、返回标准json响应并精准mock依赖;漏掉swoole协程初始化或返回非json内容会导致get()返回null、mock静默失效。

HttpTestCase 是 Hyperf 测试中用于模拟 HTTP 请求的核心基类,但它不是“开箱即用”的万能选择——用错继承关系、漏掉协程初始化、或误读响应结构,都会导致测试通过但逻辑失效。
为什么 HttpTestCase 的 get() 返回 null 或非数组?
常见现象是:接口明明返回 JSON,$this->get('/hello') 却得到 null 或字符串,断言失败。根本原因不是代码写错,而是响应未被正确解包。
-
HttpTestCase默认使用JsonPacker解析响应体,但前提是接口必须返回标准 JSON(Content-Type: application/json且 body 是合法 JSON 字符串) - 如果控制器直接
return 'hello'或echo 'hello',JsonPacker::unpack()会静默失败并返回null - 检查你的路由处理逻辑:确保返回的是
json(['hello' => 'tsh'])或response()->json(...),而非裸字符串 - 临时调试可用
var_dump((string) $res->getBody())查看原始响应内容,确认是否为 JSON 格式
HttpTestCase 必须启用协程,否则 Mock 失效
Hyperf 的依赖注入和 Mock 行为高度依赖协程上下文。若未启用,Mockery::mock() 创建的对象在协程内调用时不会触发预期行为,且不报错——这是最隐蔽的坑。
-
test/bootstrap.php中必须包含:Swoole\Runtime::enableCoroutine(true)和define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL) - 该文件需在
phpunit.xml的<php></php>段中显式引入:<server name="TEST_BOOTSTRAP" value="./test/bootstrap.php"></server> - 运行测试前执行
co-phpunit(不是原生phpunit),它会自动加载协程环境;若误用phpunit,Mock 将完全静默失效
测试类继承 HttpTestCase 还是 TestCase?
取决于你测什么。选错基类会导致方法不可用或行为异常。
- 测 HTTP 接口(如
/user/list)、需要$this->get()/$this->post()等快捷方法 → 继承HyperfTest\HttpTestCase - 测纯业务逻辑(如
UserService::createUser())、不涉及请求/响应生命周期 → 继承HyperfTest\TestCase,再手动make()服务实例 - 不要混用:
HttpTestCase内部已封装Client实例,若再手动make(Client::class)可能引发容器冲突 - 注意命名空间:
HyperfTest\HttpTestCase不是Hyperf\Testing\Client,后者是底层实现,不应直接继承
Mock 外部依赖时,Mockery::mock() 的参数必须匹配真实类型
Hyperf 的 DI 容器按接口或类名解析依赖。Mock 对象若类型声明不一致,容器将忽略它,仍注入真实实例。
- 例如服务类构造函数依赖
Psr\SimpleCache\CacheInterface,Mock 时必须写:Mockery::mock('Psr\SimpleCache\CacheInterface'),不能只写'CacheInterface' - 若依赖是具体类(如
App\Repository\UserRepository),Mock 时用完整命名空间:Mockery::mock('App\Repository\UserRepository') - 调用
$this->mock()(来自TestCase)比手写Mockery::mock()更安全,它会自动绑定到容器,且支持链式定义:$this->mock(UserRepository::class)->shouldReceive('find')->andReturn([]) - 记得在每个测试方法末尾调用
Mockery::close()(HttpTestCase已内置,无需手动加;但自定义TestCase子类需在tearDown()中补上)
bootstrap.php 中那两行协程初始化——它不报错,但会让所有 Mock 和协程调度形同虚设。很多团队花半天排查“为什么 Mock 不生效”,最后发现只是忘了这 2 行。











