测试中会发出真实HTTP请求是因为Laravel的Http门面默认不拦截,需显式调用Http::preventStrayRequests()全局禁止未mock请求,配合Http::fake()可精准控制响应并防止漏mock。

为什么测试里会发出真实 HTTP 请求?
默认情况下,Laravel 的 Http 门面(或 Illuminate\Support\Facades\Http)在测试中仍会发起真实网络请求——除非你显式拦截。这会导致测试变慢、不稳定,甚至因外部服务不可用而失败。
用 Http::preventStrayRequests() 全局拦截
这是最直接的防御方式:在测试启动时调用该方法,任何未被 mock 的 HTTP 请求都会抛出 Illuminate\Http\Client\ConnectionException。
- 推荐放在
tests/TestCase.php的setUp()中,确保每个测试都受保护 - 它不影响已通过
Http::fake()显式定义的请求行为 - 注意:仅对
Http门面有效,不拦截curl、file_get_contents或第三方 HTTP 客户端(如 Guzzle 手动实例)
protected function setUp(): void
{
parent::setUp();
Http::preventStrayRequests();
}
如何配合 Http::fake() 精准控制依赖响应?
Http::fake() 和 preventStrayRequests() 是互补关系:前者声明“哪些请求允许发生”,后者兜底“其余一律禁止”。常见组合写法:
- 只 fake 特定域名:
Http::fake(['https://api.example.com/*' => Http::response('ok', 200)]) - 对未匹配的路径,
preventStrayRequests()会立即报错,避免漏 mock - 若测试中调用了未 fake 的 URL(比如拼错地址、多了一个斜杠),错误信息类似:
Unable to connect to https://api.example.com/v1/users/ — request was not faked and stray requests are prevented.
容易忽略的边界情况
有些请求看似“内部”,实则走外部通道,容易逃过拦截:
-
Storage::disk('s3')的上传/下载可能触发 AWS SDK 的真实 HTTP 请求,需单独 mockAws\S3\S3Client - 使用
Mail::fake()只拦截邮件发送逻辑,但若邮件驱动配置为 SMTP 且未 fake,仍可能发包——应确保MAIL_MAILER=smtp时也设为log或array - 队列任务中发起的 HTTP 请求不会被当前测试上下文的
preventStrayRequests()拦截,需在任务执行前再次调用(或用Queue::fake()避免实际分发)
真正起作用的不是“有没有加这行代码”,而是是否覆盖了所有可能发起网络调用的路径——包括间接依赖。










