CakePHP 3 - 在集成测试中模拟 HTTP\Client()
CakePHP 3 - Mock HTTP\Client() in integration test
我正在使用 Cake\Http\Client
(book) 访问一些外部应用程序。在我的单元测试中,我实际上无法使用这些服务。
那么如何在控制器集成测试中模拟Http Client呢?如果我可以规定确切的响应,而无需它发出实际的 HTTP 请求,那就太好了。
在我的例子中,请求是在控制器操作中发出的,目标是同一服务器上的其他应用程序。但是,我觉得这个问题的解决方案应该独立于 HTTP 目标。
考虑到我在文档或 api 页面中找不到任何内容,我很确定没有内置解决方案来模拟 Http\Client 对象。
所以我使用了另一个 PHP HTTP 客户端 Guzzle。 Guzzle 确实允许通过排队预定义的响应来进行模拟,这正是我想要的。
但是,与 CakePHP 的顺利集成并非易事,因为 Guzzle 客户端构造函数需要传递模拟堆栈。我通过创建客户端工厂解决了这个问题:
<?php
namespace App\Guzzle;
use GuzzleHttp\Client;
/**
* Guzzle factory
*
* Created to make guzzle clients mockable
*/
class GuzzleFactory
{
static $options = [];
/**
* Create new client
*
* @return \GuzzleHttp\Client
*/
static function create()
{
return new Client(self::$options);
}
/**
* Set handler stack in global options for new clients
*
* @param \GuzzleHttp\HandlerStack $handlerStack
*/
static function setTest($handlerStack)
{
self::$options['handler'] = $handlerStack;
}
/**
* Set options array to default
*/
static function reset()
{
self::$options = [];
}
}
然后在我的控制器测试中我有以下功能:
/**
* Set Guzzle mock responses
*
* @param array $list
*/
public function setGuzzleResponses($list)
{
if (!is_array($list))
{
$list = [$list];
}
$mock = new MockHandler($list);
$handlerStack = HandlerStack::create($mock);
GuzzleFactory::setTest($handlerStack);
}
这样在测试中我可以调用:
// ...
$this->setGuzzleResponses([
new Response(200, [], json_encode($response))
]);
$this->get("/page/index"); // This request will make an HTTP call
// ...
我正在使用 Cake\Http\Client
(book) 访问一些外部应用程序。在我的单元测试中,我实际上无法使用这些服务。
那么如何在控制器集成测试中模拟Http Client呢?如果我可以规定确切的响应,而无需它发出实际的 HTTP 请求,那就太好了。
在我的例子中,请求是在控制器操作中发出的,目标是同一服务器上的其他应用程序。但是,我觉得这个问题的解决方案应该独立于 HTTP 目标。
考虑到我在文档或 api 页面中找不到任何内容,我很确定没有内置解决方案来模拟 Http\Client 对象。
所以我使用了另一个 PHP HTTP 客户端 Guzzle。 Guzzle 确实允许通过排队预定义的响应来进行模拟,这正是我想要的。
但是,与 CakePHP 的顺利集成并非易事,因为 Guzzle 客户端构造函数需要传递模拟堆栈。我通过创建客户端工厂解决了这个问题:
<?php
namespace App\Guzzle;
use GuzzleHttp\Client;
/**
* Guzzle factory
*
* Created to make guzzle clients mockable
*/
class GuzzleFactory
{
static $options = [];
/**
* Create new client
*
* @return \GuzzleHttp\Client
*/
static function create()
{
return new Client(self::$options);
}
/**
* Set handler stack in global options for new clients
*
* @param \GuzzleHttp\HandlerStack $handlerStack
*/
static function setTest($handlerStack)
{
self::$options['handler'] = $handlerStack;
}
/**
* Set options array to default
*/
static function reset()
{
self::$options = [];
}
}
然后在我的控制器测试中我有以下功能:
/**
* Set Guzzle mock responses
*
* @param array $list
*/
public function setGuzzleResponses($list)
{
if (!is_array($list))
{
$list = [$list];
}
$mock = new MockHandler($list);
$handlerStack = HandlerStack::create($mock);
GuzzleFactory::setTest($handlerStack);
}
这样在测试中我可以调用:
// ...
$this->setGuzzleResponses([
new Response(200, [], json_encode($response))
]);
$this->get("/page/index"); // This request will make an HTTP call
// ...