как выполнить модульный вызов curl в php

Как бы вы шли на модульное тестирование выполнения завитка?

public function get() { $ch = curl_init($this->request->getUrl()); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); curl_close($ch); if (!strstr($type, 'application/json')) { throw new HttpResponseException('JSON response not found'); } return new HttpResponse($code, $result); } 

Мне нужно проверить возвращаемый тип содержимого, чтобы он мог генерировать исключение.

Solutions Collecting From Web of "как выполнить модульный вызов curl в php"

Как предложил thomasrutter, создайте класс для абстрактного использования функций cURL.

 interface HttpRequest { public function setOption($name, $value); public function execute(); public function getInfo($name); public function close(); } class CurlRequest implements HttpRequest { private $handle = null; public function __construct($url) { $this->handle = curl_init($url); } public function setOption($name, $value) { curl_setopt($this->handle, $name, $value); } public function execute() { return curl_exec($this->handle); } public function getInfo($name) { return curl_getinfo($this->handle, $name); } public function close() { curl_close($this->handle); } } 

Теперь вы можете протестировать, используя макет интерфейса HttpRequest не вызывая никаких функций cURL.

 public function testGetThrowsWhenContentTypeIsNotJson() { $http = $this->getMock('HttpRequest'); $http->expects($this->any()) ->method('getInfo') ->will($this->returnValue('not JSON')); $this->setExpectedException('HttpResponseException'); // create class under test using $http instead of a real CurlRequest $fixture = new ClassUnderTest($http); $fixture->get(); } 

Редактировать Исправлена ​​простая ошибка синтаксического анализа PHP.

Не используйте curl напрямую, а через оболочку, такую ​​как HTTP_Request2 PEAR. Благодаря этому у вас есть возможность обмениваться драйвером curl с макетным драйвером – идеально подходит для модульных тестов.

Я наткнулся на этот вопрос, когда я пытался проверить класс, используя cURL. Я принял совет Дэвида Харкнесса к сердцу и создал интерфейс для cURL. Тем не менее, функция заглушки / макета, предоставленная PHPUnit, в моем случае была недостаточной, поэтому я добавил свою собственную реализацию заглушки интерфейса и поместил все это в GitHub. И поскольку этот вопрос проявляется довольно рано на Google при поиске этой проблемы, я подумал, что разместил ее здесь, чтобы другие могли сэкономить усилия.

Вот.

В вики-репозитории содержится довольно подробная документация о возможностях заглушки, но здесь они короткие.

Интерфейс представляет собой сопоставление функций cURL PHP с 1: 1, чтобы было очень легко начать использовать интерфейс (просто SAI_CurlInterface свой ClassUnderTest экземпляр, реализующий SAI_CurlInterface а затем вызовите все функции cURL, как и раньше, но как методы в этом экземпляре) , Класс SAI_Curl реализует этот интерфейс, просто делегируя cURL. Теперь, если вы хотите протестировать ClassUnderTest вы можете предоставить ему экземпляр SAI_CurlStub .

Заглушка в основном устраняет проблему, из-за которой mocks и заглушки PHPUnit не могут возвращать фиктивные данные в зависимости от прежних вызовов функций (но так работает cURL – вы настраиваете свои параметры, а ответ, код ошибки и cURL-информация зависят от этих параметров). Итак, вот краткий пример, показывающий эти возможности для ответов (для кодов ошибок и cURL-info, см. Wiki).

 public function testGetData() { $curl = new SAI_CurlStub(); // Set up the CurlStub $defaultOptions = array( CURLOPT_URL => 'http://www.myserver.com' ); $chromeOptions = array( CURLOPT_URL => 'http://www.myserver.com', CURLOPT_USERAGENT => 'Chrome/22.0.1207.1' ); $safariOptions = array( CURLOPT_URL => 'http://www.myserver.com', CURLOPT_USERAGENT => 'Safari/537.1' ); $curl->setResponse('fallback response'); $curl->setResponse('default response from myserver.com' $defaultOptions); $curl->setResponse('response for Chrome from myserver.com', $chromeOptions); $curl->setResponse('response for Safari from myserver.com', $safariOptions); $cut = new ClassUnderTest($curl); // Insert assertions to check whether $cut handles the // different responses correctly ... } 

Вы можете сделать свой ответ зависимым от любой комбинации любых cURL-опций. Конечно, вы можете это сделать еще дальше. Скажем, например, ваш ClassUnderTest принимает некоторые данные XML с сервера и анализирует его (ну, у вас должно быть два отдельных класса для этих задач, но давайте предположим это для нашего примера), и вы хотите проверить это поведение. Вы можете загрузить ответ XML вручную, и попросите свой тест прочитать данные из файла и передать его в ответ. Тогда вы точно знаете, какие данные есть, и можете проверить, правильно ли он разбирается. Кроме того, вы можете реализовать SAI_CurlInterface загрузку всех ответов из вашей файловой системы сразу, но существующая реализация, безусловно, является точкой начала.

В то время, когда я пишу этот ответ, @ SAI_CurlStub @ еще не поддерживает функции cURL multi-lib, но я планирую реализовать это тоже в будущем.

Я надеюсь, что этот заглушка поможет всем, кто хочет объединить тесты cURL-зависимых классов. Не стесняйтесь проверять и использовать классы, или вносить свой вклад, конечно же – это на GitHub в конце концов :). Кроме того, я открыт для любой конструктивной критики в отношении реализации и использования интерфейса и заглушки.

Один из подходов к этому заключается в замене используемого интерфейса (в данном случае, функций curl_) с фиктивными версиями самих себя, которые возвращают определенные значения. Если бы вы использовали объектно-ориентированную библиотеку, это было бы проще, потому что вы могли бы просто заменить фиктивный объект, который имеет те же имена методов (и, действительно, фреймворки, такие как simpletest, могут легко настроить методы фиктивных объектов). В противном случае, возможно, есть и другое колдовство, которое вы можете использовать для переопределения встроенных функций с манекенами. Это расширение включает override_function (), который выглядит так, как вам нужно, хотя это добавит другую зависимость.

Если вы хотите протестировать это, не заменяя функции curl_ фиктивными версиями, похоже, вам нужно будет настроить фиктивный сервер, который вернет определенный результат, чтобы вы могли проверить, как ваш PHP и его расширение curl обрабатывают это результат. Чтобы полностью протестировать его, вам нужно получить доступ к этому через HTTP, а не, скажем, к локальному файлу, потому что ваш PHP зависит от кода ответа HTTP и т. Д. Таким образом, ваши тесты потребуют функционирования HTTP-сервера.

Кстати, PHP 5.4 фактически будет включать в себя собственный веб-сервер, который пригодится для этой цели. В противном случае вы можете поместить тестовый скрипт на известный сервер, которым вы управляете, или распределить простую конфигурацию сервера с вашими тестами.

Если бы вы использовали фактический сервер для тестирования, это бы стало менее единичным тестом и более тестом на интеграцию, потому что вы тестируете как ваш PHP, так и сервер, и интеграцию между ними. Вы также пропустили бы возможность проверить по требованию, как ваш код обрабатывает определенные сбои.

Вы можете использовать библиотеку функций mock. Я сделал один для вас: php-mock-phpunit

 namespace foo; use phpmock\phpunit\PHPMock; class BuiltinTest extends \PHPUnit_Framework_TestCase { use PHPMock; public function testCurl() { $curl_exec = $this->getFunctionMock(__NAMESPACE__, "curl_exec"); $curl_exec->expects($this->once())->willReturn("body"); $ch = curl_init(); $this->assertEquals("body", curl_exec($ch)); } } 

В тестовом request->getUrl() возвращает URI локального файла, который, как вы знаете, request->getUrl() исключение.