Avillions
@Avillions
PHP Developer at Genesis

Как в Symfony3.4 + Codeception при написании функциональных тестов замокать сервис в DI?

Добрый день, есть приложение на Symfony3.4 которое предоставляет REST API обертку над сторонним сервисом.

Работа со сторонним сервисом происходит в классе который инициализируется в DI как сервис:

AppBundle/Resources/config/services.yml
app.service.third_party_service:
        class: AppBundle\Service\ThirdPartyService
        arguments:
            - "%third_party_service.url%"
            - "@event_dispatcher"


Код самого класса AppBundle\Service\ThirdPartyService.php
/**
 * Class ThirdPartyService
 * @package AppBundle\Service
 */
class ThirdPartyService implements ThirdPartyInterface
{
    /**
     * @param string $username
     * @param string $password
     * @return bool
     */
    public function login(string $username, string $password): bool
    {
        //some php code
    }

    /**
     * @param string $email
     * @param string $username
     * @param string $password
     * @return bool
     */
    public function register(string $email, string $username, string $password): bool
    {
        //some php code
    }
}


Нужно написать функциональные Codeception тесты на REST API приложения, только что бы сервис app.service.third_party_service не делал запросов на стороннее приложение, т.е. нужно замокать методы этого сервиса на определенные ответы.

Есть конфиг функциональных тестов tests/functional.suite.yml:
actor: FunctionalTester
modules:
    enabled:
        - Symfony:
            app_path: 'app'
            environment: 'test'
            debug: true
            part: SERVICES
        - Doctrine2:
            depends: Symfony
        - REST:
            depends: PhpBrowser
            url: http://localhost/app_dev.php/api/v1
        - \Helper\Functional


Есть сам тест tests/functional/AccountLoginCest.php:
class AccountLoginCest
{
    /**
     * @param FunctionalTester $I
     */
    public function testSuccessfulLogin(FunctionalTester $I)
    {
        $thirdPartyService = $I->grabService('app.service.third_party_service');

        dump($thirdPartyService);

        $I->sendPOST('/account/login', [
            'login'    => 'test',
            'password' => 'test',
        ]);

        $I->seeResponseCodeIs(HttpCode::OK);
    }
}


В тесте я получил доступ к сервису app.service.third_party_service, но я не могу понять как сделать так что бы метод login этого сервиса возвращал true для тестовых данных.

Я вижу тут два варианта:
1) Хардкодом в сервисе делать проверки на тестовые данные, и в случае если это они, то не делать запрос на сторонний веб сервис а сразу вернуть true;
2) Создать environment test, и в конфиге app/config/config_test.yml сделать декоратор app.service.third_party_service. Сам environment в тестах передавать как параметр в url.

Оба эти варианта хоть и подходят но с моей точки зрения очень убоги, помогите плиз совет как можно человеческим образом замокать app.service.third_party_service?
  • Вопрос задан
  • 590 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы