У меня есть функция, которая выглядит следующим образом:
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()
метод?
Не так много вы можете сделать с time
так как это нативная функция и не может быть посмешищем. Вы можете слегка изменить его для тестируемости на что-то вроде:
class TimeGetter
{
public function getTime()
{
return time();
}
}
а затем использовать как
$currentDatetime = $this->timeGetter->getTime();
// instead of $currentDatetime = time();
Таким образом, вы можете высмеять его позже и вернуть в любое время, когда вам нужно проверить свою функциональность.
Ни вы не можете создать макет для \Aws\S3\Transfer
, поскольку вы явно создаете новый экземпляр в 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('\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 в официальные документы.
Других решений пока нет …