0

我有一个看起来像这样的函数:

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 \Aws\S3\Transfer($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 秒异步点击一个自定义端点。

在这种情况下,我将如何模拟\Aws\S3\Transfer对象,以便它包含返回的promise()方法,而该方法又返回该wait()方法?

4

1 回答 1

1

你无能为力,time因为它是一个原生函数,不能被模拟。为了可测试性,您可以稍微重构它,例如:

class TimeGetter
{
    public function getTime()
    {
        return time();
    }
}

然后用作

$currentDatetime = $this->timeGetter->getTime();
// instead of $currentDatetime = time();

因此,您可以稍后对其进行模拟,并返回您需要测试功能的任何时间。

你也不能为 . 创建一个 mock \Aws\S3\Transfer,因为你在instantiateS3TransferObject.

对于其余代码,您需要同时模拟Guzzlecurl。基于问题中的代码片段的非常粗略的近似值:

// 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('\whatever\curl\class\you\use')
    ->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 。

于 2016-01-18T18:29:12.270 回答