我有一个函数,看起来像:
public function downloadProjectFolder($projectId, $taskToken){
// Download the project directory if it isn't on the server
if(is_dir('/path/to/folder/') === false){
$manager = $this->instantiateS3TransferObject($projectId, $taskToken);
$promise = $manager->promise();
$promise->wait();
}
else{
return 'Project Folder Already Exists';
}
}
如果本地计算机上尚不存在文件夹,上述方法会将文件夹从 AWS S3 下载到我的服务器上。 实际的 S3 Transfer 对象(来自 AWS PHP SDK V3 库 - 该库本身主要从 Guzzle PHP 抽象而来)由以下函数实例化:
private function instantiateS3TransferObject($projectId, $taskToken){
$lastDatetime = time();
return new AwsS3Transfer($this->myS3ClientObject, 's3://mys3bucket/destination/url',
'/path/to/local/directory/', array(
'base_dir' => 'destination/url',
'before' => function()use($projectId, $taskToken, &$lastDatetime){
$currentDatetime = time();
if(($currentDatetime - $lastDatetime) >= 30){
$postParams = array(
'project_id' => $projectId,
'task_token' => $taskToken
);
$this->curl->post($postParams, 'http://url/endpoint');
$lastDatetime = $currentDatetime;
}
}
)
);
}
上面基本上开始我的文件夹下载,并每 30 秒异步命中一次自定义端点。
在这种情况下,我将如何模拟AwsS3Transfer
对象,以便它在返回时包含promise()
方法,而该方法又返回wait()
方法?
你对time
无能为力,因为它是一个本机函数,不能被嘲笑。为了可测试性,您可以稍微重构它,如下所示:
class TimeGetter
{
public function getTime()
{
return time();
}
}
然后用作
$currentDatetime = $this->timeGetter->getTime();
// instead of $currentDatetime = time();
因此,您可以稍后模拟它,并在测试功能所需的任何时间返回。
您也不能为 AwsS3Transfer
创建模拟,因为您在 instantiateS3TransferObject
中显式创建了一个新实例。
对于其余代码,您需要模拟Guzzle
和curl
。基于问题中代码片段的非常粗略的近似值:
// First Guzzle, but order doesn't matter:
$mock = new MockHandler([
// first expected request
function($_self, RequestInterface $request, array $options) {
// assert $request values meet expectations
// and return response or exception you expect from S3
return new Response(200, ['X-Foo' => 'Bar']);
},
// second expected request, if any, is either instance of Response, Exception, or a function which returns one of them
// third expected request, etc...
]);
$handler = HandlerStack::create($mock);
// then pass it to the class under test
// assuming it is public:
$cut->myS3ClientObject = new Client(['handler' => $handler]);
// Now curl:
$curlMock = $this->getMockBuilder('whatevercurlclassyouuse')
->disableOriginalConstructor()
->setMethods(['post'])
->getMock();
$curlMock
->expects($this->once()) // twice, exact, etc ...
->method('post')
->with(
$this->equalTo(['project_id' => 'expected_project_id', 'task_token' => 'expected_token' ]),
$this->equalTo('http://url/endpoint')
);
//again, assuming it is public
$cut->curl = $curlMock;
// then actually execute the method you are testing:
$cut-> downloadProjectFolder('expected_project_id', 'expected_token');
您可以在官方文档中阅读更多如何测试 Guzzle。