Функциональное тестирование и внешний API

Я пишу приложение facebook, используя фреймворк, который следует шаблону MVC - Kohna 3.2. Я хочу протестировать свой серверный код. Я решил написать модульные тесты для моделей и функциональные тесты для проверки контроллеров / представлений. Решил использовать PHPUnit для обоих.

Так что я быстро столкнулся с проблемой. Как я могу написать функциональный тест для контроллера, который использует внешний API во время обработки запроса?

Я не хочу использовать настоящие вызовы API. Их выполнение занимает много времени и требует токена аутентификации в сеансе, срок действия которого истекает в ближайшее время. Кроме того, тестирование таких вещей, как «написание сообщений на стене», может вызвать много спама.

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

Как бы ты это сделал?


person Luigi    schedule 02.08.2012    source источник
comment
Итак, вы хотите реализовать поддельный API для тестирования своего кода? Я прав?   -  person s.webbandit    schedule 31.08.2012


Ответы (2)


1) При тестировании чего-то, что работает с оболочкой API, вы должны имитировать весь класс оболочки API и имитировать выдачу исключений в виде состояний ошибки и тестирования того, как само приложение будет реагировать на эти исключения.

Вероятно, он должен прекратить выполнение некоторых операций, которые зависели от ответа API, и, вероятно, должен показать некоторую удобную для пользователя ошибку.

Более того, вы можете (и, вероятно, должны) проверить, какие методы в оболочке API были вызваны + сколько раз и какие параметры были переданы.

<?php

public function testShowUser() {
    $fb = $this->getMock( 'Facebook\Api' );
    $fb->expects( $this->once() ) // if your library will call getUserInfo() more than once or never, the test will fail
        ->method( 'getUserInfo' )
        ->with( $this->equalTo( 'johndoe' ) ) // if the method will be called with different parameter, the test will fail
        ->will( $this->throwException( 'Facebook\NonExistingUser' ) );

    $myApp = new MyApp( $fb );
    $myApp->renderUser( 'johndoe' ); // if this will throw uncaught exception, the test will fail

    $this->assertEquals(
        array( 'The user you requested does not exist' ),
        $myApp->getFlashMessages()
    );
}

2) При тестировании самой оболочки API вы можете имитировать необработанный ответ API.

Вы должны разделить все, что связано с HTTP-связью, с каким-то конкретным классом (оболочка Curl / со своими собственными модульными тестами /) и предположить, что сервер вернул какой-то конкретный код HTTP и ответ.

Вы можете сохранить все возможные типы ответов в файлы, чтобы вы могли загружать их в свои тесты в качестве ответа.

Я бы посоветовал сделать это так:

<?php

/**
 * @expectedException Facebook\NonExistingUser
 */
public function testUnavailableApi() {
    $curl = $this->getMock( 'CurlWrapper' );
    $curl->expects( $this->once() )
        ->method( 'getBody' )
        ->will( $this->returnValue( file_get_contents( 'fb_404_response.json' ) ) );
    $curl->expects( $this->once() )
        ->method( 'getStatusCode' )
        ->will( $this->returnValue( 404 ) );

    $api = new Facebook\Api( $curl );
    $api->getUserInfo( 'johndoe' );
}
person Radek Simko    schedule 05.09.2012
comment
Я умею издеваться над вещами. Мне просто интересно, как я мог внедрить эти макеты, когда я создаю запросы и проверяю их результаты. С момента публикации этого вопроса лучший ответ, который я получил до сих пор, - использовать контейнер для инъекций зависимостей и настроить его для использования макета в тесте перед подделкой запроса. - person Luigi; 11.09.2012

Просматривая свои собственные вопросы, на которые нет ответа, я могу ответить себе, что использование DIC (контейнера для внедрения зависимостей) является ответом. Это позволяет иметь различную конфигурацию для тестовой среды, или при использовании одного процесса PHP во время тестирования даже можно настроить макеты непосредственно перед выполнением теста.

person Luigi    schedule 02.07.2013