来自 Guzzle 的 PHPUnit 和模拟请求

Posted

技术标签:

【中文标题】来自 Guzzle 的 PHPUnit 和模拟请求【英文标题】:PHPUnit and mock request from Guzzle 【发布时间】:2018-08-07 08:32:59 【问题描述】:

我有一个具有以下功能的课程:

public function get(string $uri) : stdClass

    $this->client = new Client;
    $response = $this->client->request(
        'GET',
        $uri,
        $this->headers
    );

    return json_decode($response->getBody());

如何模拟来自 phpUnit 的请求方法?我尝试了不同的方法,但它总是尝试连接到指定的 uri。

我试过了:

    $clientMock = $this->getMockBuilder('GuzzleHttp\Client')
        ->setMethods('request')
        ->getMock();

    $clientMock->expects($this->once())
        ->method('request')
        ->willReturn('');

但这没有用。我能做些什么?我只需要将响应模拟为空。

谢谢

PD : 客户端来自(使用 GuzzleHttp\Client)

【问题讨论】:

$this->client 是如何初始化的,你是如何通过模拟的? 你不需要返回一个实现 ResponseInterface 的对象而不是一个字符串吗?否则当你调用getBody时它会爆炸。 当然,你的模拟应该返回一个ResponseInterface 存根,这样getBody 才能工作(你也必须模拟这个) 另外docs.guzzlephp.org/en/stable/testing.html 可能比 PHPUnit 模拟更好 我想用phpunit mocks 【参考方案1】:

我认为建议最好使用http://docs.guzzlephp.org/en/stable/testing.html#mock-handler

因为它看起来是正确执行此操作的最优雅方式。

谢谢大家

【讨论】:

Guzzle 6 的 URL(固定和基于正则表达式)模拟处理程序 - tarampampam/guzzle-url-mock 这是最好的方法吗?我看不到验证您是否向 guzzle 客户端发送正确参数的方法,只是模拟响应。【参考方案2】:

模拟的响应不需要特别是任何东西,您的代码只希望它是一个具有getBody 方法的对象。因此,您可以只使用stdClassgetBody 方法,该方法返回一些json_encoded 对象。比如:

$jsonObject = json_encode(['foo']);
$uri = 'path/to/foo/bar/';

$mockResponse = $this->getMockBuilder(\stdClass::class)->getMock();

$mockResponse->method('getBody')->willReturn($jsonObject);

$clientMock = $this->getMockBuilder('GuzzleHttp\Client')->getMock();

$clientMock->expects($this->once())
    ->method('request')
    ->with(
        'GET', 
        $uri,
        $this->anything()
    )
    ->willReturn($mockResponse);

$result = $yourClass->get($uri);

$expected = json_decode($jsonObject);

$this->assertSame($expected, $result);

【讨论】:

【参考方案3】:

我更喜欢这种方式来模拟 PHP 中的客户端。在此示例中,我使用的是 Guzzle 客户端。

克隆代码或通过 composer 安装

$ composer require doppiogancio/mocked-client

然后……

$builder = new HandlerStackBuilder();

// Add a route with a response via callback
$builder->addRoute(
    'GET', '/country/IT', static function (ServerRequestInterface $request): Response 
        return new Response(200, [], '"id":"+39","code":"IT","name":"Italy"');
    
);

// Add a route with a response in a text file
$builder->addRouteWithFile('GET',  '/country/IT/json', __DIR__ . '/fixtures/country.json');

// Add a route with a response in a string
$builder->addRouteWithFile('GET',  '"id":"+39","code":"IT","name":"Italy"');

// Add a route mocking directly the response
$builder->addRouteWithResponse('GET', '/admin/dashboard', new Response(401));

$client = new Client(['handler' => $builder->build()]);

一旦你模拟了客户端,你就可以像这样使用它:

$response = $client->request('GET', '/country/DE/json');
$body = (string) $response->getBody();
$country = json_decode($body, true);

print_r($country);

// will return
Array
(
    [id] => +49
    [code] => DE
    [name] => Germany
)

【讨论】:

以上是关于来自 Guzzle 的 PHPUnit 和模拟请求的主要内容,如果未能解决你的问题,请参考以下文章

使用 PHPUnit 在 Laravel 控制器中进行单元测试 Guzzle

在 laravel5.8 中来自 guzzle 的 oauth2 访问密钥请求

来自另一个类的 PHPUnit 模拟方法

如何从 guzzle 请求中获取和显示图像

Laravel PHPUnit 模拟请求

php与其他一些相关工具的安装步骤分享