如何使用GuzzleHttp MockHandler延迟5秒返回Mock响应?
问题描述
我有以下PHP/PHPUnit代码:
<?php namespace Experiments\Tests; use GuzzleHttp\Client as HttpClient; use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\HandlerStack; use GuzzleHttp\Psr7\Response; use GuzzleHttp\RequestOptions; use PHPUnit\Framework\TestCase; final class ApiGatewayTest extends TestCase { public function testExecute() { $req = json_decode('{ "root": { "param1": [ "value1" ] } }', true); $resp = '{ "echo": { "root": { "param1": [ "value1" ] } } }'; $options = [ RequestOptions::HEADERS => [ 'Content-Type' => 'application/json', ], RequestOptions::JSON => $req, RequestOptions::TIMEOUT => 10, ]; $handlerStack = HandlerStack::create( new MockHandler([new Response(200, ['Content-Type' => 'application/json'], $resp)]) ); $client = new HttpClient(['handler' => $handlerStack]); $response = $client->request( 'POST', 'whatever-just-mocking', $options ); $responseBodyJson = (string) $response->getBody(); $responseBody = json_decode($responseBodyJson, true); $this->assertSame('value1', $responseBody['echo']['root']['param1'][0]); } }
上述单元测试运行正常,可通过以下命令测试:
$ ./vendor/bin/phpunit --filter 'testExecute\b'
我需要让Mock响应延迟5秒返回,以便在上述测试类中实现并测试超时处理逻辑,请问该如何实现?
实现方法
要给Guzzle的Mock响应添加延迟,你可以利用MockHandler结合匿名函数模拟延迟逻辑,同时调整超时时间触发超时异常,具体步骤如下:
- 在MockHandler的响应列表中,用匿名函数替代直接返回Response对象,在函数内部加入
sleep(5)模拟服务端延迟 - 将请求的超时时间设置为小于延迟的数值(比如3秒),触发Guzzle的超时异常
- 通过PHPUnit的断言方法验证超时异常是否抛出,完成超时逻辑测试
修改后的测试代码示例:
<?php namespace Experiments\Tests; use GuzzleHttp\Client as HttpClient; use GuzzleHttp\Exception\ConnectException; use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\HandlerStack; use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Request; use GuzzleHttp\RequestOptions; use PHPUnit\Framework\TestCase; final class ApiGatewayTest extends TestCase { public function testExecuteTimeout() { $req = json_decode('{ "root": { "param1": [ "value1" ] } }', true); $resp = '{ "echo": { "root": { "param1": [ "value1" ] } } }'; // 设置超时时间为3秒,短于模拟的5秒延迟,确保触发超时 $options = [ RequestOptions::HEADERS => [ 'Content-Type' => 'application/json', ], RequestOptions::JSON => $req, RequestOptions::TIMEOUT => 3, ]; $mockHandler = new MockHandler([ // 用匿名函数模拟带延迟的响应 function (Request $request) use ($resp) { sleep(5); // 模拟5秒延迟 return new Response(200, ['Content-Type' => 'application/json'], $resp); } ]); $handlerStack = HandlerStack::create($mockHandler); $client = new HttpClient(['handler' => $handlerStack]); // 断言会抛出超时相关的异常 $this->expectException(ConnectException::class); $this->expectExceptionMessageMatches('/timeout/'); $client->request( 'POST', 'whatever-just-mocking', $options ); } }
关键细节
- 匿名函数接收
Request对象作为参数,执行休眠逻辑后返回Response,完美模拟真实请求的延迟场景 - 超时时间需小于模拟的延迟时长,否则无法触发超时异常
- 使用
expectException和expectExceptionMessageMatches精准断言超时异常的类型和内容,确保超时逻辑符合预期
运行测试的命令:
$ ./vendor/bin/phpunit --filter 'testExecuteTimeout\b'
内容的提问来源于stack exchange,提问作者Viewsonic
相关产品推荐
相关产品推荐

