Как я могу смоделировать автосвязь с контроллером Symfony в функциональных тестах phpunit? - PullRequest
0 голосов
/ 03 июня 2018

Непроблемный контекст

Допустим, в Symfony 3.3 у нас есть контроллер по умолчанию, который пишет «Hello, world!»:

class DefaultController extends Controller
{
    public function indexAction() : Response
    {
        return new Response( 'Hello, world!' );
    }
}

Если я хочу его протестировать, я простосоздайте WebTestCase и сделайте некоторые утверждения на клиенте или сканере, например,

class DefaultControllerTest extends WebTestCase
{
    public function testIndex()
    {
        $client = static::createClient();

        $crawler = $client->request( 'GET', '/route/to/hello-world/' );

        $this->assertEquals( 200, $client->getResponse()->getStatusCode() );
        $this->assertContains( 'Hello', $crawler->filter( 'body' )->text() );
    }
}

Это просто отлично работает.

Проблемный контекст

Допустим, у нас есть какой-то модульуслуги.Например, сервис IdGenerator, который создает новые идентификаторы на основе определенного алгоритма, когда он нам нужен, и они представляют собой простой текст:

class IdGenerator
{
    public function generateNewId() : string;
}

Скажем, мы внедряем его с помощью autowiring в контроллер.И мы ожидаем, что контроллер скажет что-то вроде Hello, world, on request 8bfcedbe1bf3aa44e0545375f0e52f6b969c50fb!, откуда эта группа символов поступает из IdGenerator.

class DefaultController extends Controller
{
    public function indexAction( IdGenerator $idGenerator ) : Response
    {
        $id = $idGenerator->generateNewId();
        $message = sprintf( 'Hello, world, on request %s!', $id );
        return new Response( $message );
    }
}

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

Но это не тот случай, когда автоматизированные тесты должны появиться в мире.Мы должны посмеяться над IdGenerator, чтобы он возвращал определенный id, чтобы утверждать:

class DefaultControllerTest extends WebTestCase
{
    public function testIndex()
    {
        $id = 'test-id-test-id-test-id';
        $idGenerator = $this->createMock( IdGenerator::class );
        $idGenerator->method( 'generateNewId' )->willReturn( $id );

        // What do I have to do with $idGenerator now here????

        $client = static::createClient();

        // Do something else here?

        $crawler = $client->request( 'GET', '/admin/flights/search/' );

        $this->assertEquals( 200, $client->getResponse()->getStatusCode() );
        $this->assertContains( $id, $crawler->filter( 'body' )->text() );
    }
}

Я уже проверял, чтобы получить контейнер из ядра, из клиента и установить там службу и ее не работает:

    $id = 'test-id-test-id-test-id';
    $idGenerator = $this->createMock( IdGenerator::class );
    $idGenerator->method( 'generateNewId' )->willReturn( $id );

    $client = static::createClient();
    $kernel = $client->getKernel();
    $container = $kernel->getContainer();
    $container->set( 'My\Nice\Project\Namespace\IdGenerator', $idGenerator );

Он все еще получает автонастройку вместо той, которую я хочу (макет).

Вопрос

Какя могу настроить WebTestCase так, чтобы автоматическая проводка подключала мой поддельный сервис?

1 Ответ

0 голосов
/ 03 июня 2018

Короткий ответ - нет.

WebTestCase предназначен для тестов более высокого уровня, иногда называемых функциональными или интеграционными тестами.Они предназначены для использования реальных сервисов или соответствующих альтернативных тестов, например, базы данных SQLite для тестов вместо MySQL или песочницы Paypal вместо производственного сервиса.Если вы хотите протестировать сервис и заменить его зависимости на макет или заглушку, вы должны вместо этого написать модульный тест.

Если вы хотите заменить сервис на фиктивную реализацию, например такую, которая всегда возвращает одно и то жеИдентификатор или хэш, основанный на вводе, можно заменить псевдонимом в конфигурации контейнера в вашем config/services_test.yaml, который будет использоваться всякий раз, когда ваше приложение использует среду тестового приложения (что по умолчанию делает WebTestCase).Вы также можете попробовать изменить контейнер во время выполнения, но поскольку Symfony компилирует контейнер, а затем замораживает его, то есть не допускает никаких изменений в контейнере, это может быть сложно и не очень рекомендуется.

Как дальнейшеессылка Symfony 4.1 предоставляет контейнер со всеми службами, включая частные, которые доступны: https://symfony.com/blog/new-in-symfony-4-1-simpler-service-testing Это, скорее всего, не поможет в вашем случае, но показывает, как вы можете взаимодействовать с контейнером служб в тестах WebTestCase.

...