在日常开发中,我们经常需要与外部API进行交互。但在测试阶段,直接调用真实API会带来一系列问题:测试速度慢、API限制、网络依赖等。Laravel的HTTP客户端提供了一个极其强大的测试工具——Http::fake(),让我们能够优雅地解决这些问题。
什么是Http::fake?
Laravel的HTTP客户端提供了一个专门用于测试的伪造功能,可以让你"拦截"发出的请求并返回预设的响应。这意味着你可以在测试中模拟任何外部API的响应,而无需实际发出网络请求。
基本用法非常简单:
use Illuminate\Support\Facades\Http;
// 伪造所有HTTP请求
Http::fake();
// 发起请求(将返回空的200响应)
$response = Http::get('https://api.example.com/data');
这样,所有的HTTP请求都会返回一个空的200状态码响应,而不会真正发送请求到外部服务器。
实际应用场景
1. 伪造特定URL的响应
最常见的场景是针对特定API端点伪造响应:
Http::fake([
// 伪造GitHub API的响应
'github.com/*' => Http::response(['id' => 1, 'name' => 'laravel'], 200),
// 伪造Google API的响应
'google.com/*' => Http::response('Hello World', 200),
]);
// 这将返回伪造的GitHub响应
$response = Http::get('https://github.com/api/users/1');
使用通配符*可以匹配同一域名的所有端点,非常灵活。
2. 模拟响应序列
当需要测试API返回多个不同响应的情况时,可以使用响应序列:
Http::fake([
'api.example.com/*' => Http::sequence()
->push(['data' => 'first response'], 200)
->push(['data' => 'second response'], 200)
->pushStatus(404), // 最后返回404错误
]);
// 第一次调用返回第一个响应
$first = Http::get('https://api.example.com/data');
// 第二次调用返回第二个响应
$second = Http::get('https://api.example.com/data');
// 第三次调用返回404
$third = Http::get('https://api.example.com/data');
这对于测试分页、错误处理等场景非常有用。
3. 使用回调函数动态伪造
对于更复杂的场景,可以使用回调函数动态生成响应:
Http::fake(function ($request) {
// 根据请求内容决定返回什么响应
if (str_contains($request->url(), 'users')) {
return Http::response(['user' => 'John'], 200);
}
return Http::response('Not found', 404);
});
这种方式提供了极大的灵活性,可以根据请求的方法、URL、参数等动态决定返回内容。
4. 防止测试中的杂散请求
在测试中,我们希望确保没有意外的外部请求发生。Laravel提供了预防措施:
// 在测试类的setUp方法中
public function setUp(): void
{
parent::setUp();
Http::preventStrayRequests();
}
// 然后只伪造你期望的请求
Http::fake([
'expected-api.com/*' => Http::response('OK', 200),
]);
// 这将正常执行
Http::get('https://expected-api.com/data');
// 这将抛出异常,因为未伪造此请求
Http::get('https://unexpected-api.com/data');
这种方法可以确保测试只与你预期的API交互,提高测试的可靠性。
验证请求是否被发送
除了伪造响应,你还可以验证特定的请求是否被正确发送:
Http::fake();
// 执行你的代码,可能会发送HTTP请求
app(CallExternalApi::class)->execute();
// 断言特定请求被发送
Http::assertSent(function ($request) {
return $request->url() === 'https://api.example.com/data' &&
$request->hasHeader('Authorization', 'Bearer token123');
});
// 断言特定请求未被发送
Http::assertNotSent(function ($request) {
return $request->url() === 'https://api.other.com/data';
});
// 断言请求数量
Http::assertSentCount(3);
这些断言方法让测试更加完善,可以验证代码是否正确地尝试与外部API通信。
写在最后
Laravel的Http::fake()是一个极其强大的测试工具,它可以:
- 提高测试速度(无需网络请求)
- 增加测试可靠性(消除外部依赖)
- 覆盖各种场景(成功、失败、异常情况)
- 验证代码是否正确发送请求
通过熟练使用这一功能,你可以为涉及HTTP请求的代码编写高质量、快速且可靠的测试,大大提升项目的稳定性和可维护性。