Как протестировать общий пакет Symfony 2 без полного проекта

#git #symfony #phpunit #bundle #composer-php

#git #symfony #phpunit #пакет #композитор-php

Вопрос:

Поскольку мы начинаем использовать Symfony 2 в нескольких проектах, мы обнаруживаем, что существует довольно много кода, которым мы могли бы поделиться между нашими проектами. Итак, мы начали извлекать функции в пакеты Symfony 2, чтобы разделить их между нашими проектами.

Хотя у нас в основном все работает, остается довольно много вопросов, которые нелегко найти в Google, особенно когда дело доходит до тестирования общего пакета.

Первый небольшой пакет, который мы извлекли, содержит объект Doctrine, kernel.event_listener который автоматически вводится в DI-контейнер клиентского проекта, аннотацию, другую службу и пару команд. Основная идея заключается в том, что клиентский проект может аннотировать свои контроллеры нашей аннотацией, event_listener будет перехватывать запросы к аннотированным контроллерам и выполнять некоторую дополнительную логику (с участием сущности doctrine), прежде чем в конечном итоге будет вызван контроллер. Команды предназначены для администрирования записей базы данных объекта doctrine.

Пока все работает именно так, как мы ожидали, но мы боремся с проверяемостью только пакета. Во-первых, репозиторий Git, в котором хранится пакет, не содержит полного проекта Symfony2. Это было бы излишним, поскольку мы создаем здесь только пакет, а не целое приложение, верно?

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

Как мы можем протестировать команды? Нам нужно было бы смоделировать базу данных, лежащую в основе doctrine. Когда мы пытаемся выполнить команду в тесте phpunit, который просто загружается /vendor/autoload.php , конечно, мы получаем:

Фатальная ошибка: вызов неопределенного метода SymfonyComponent ConsoleApplication::getKernel() в /…/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Command/ContainerAwareCommand.php в строке 3

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

Чего мне не хватает? Есть ли какая-либо документация о разработке пакетов только для пакетов / без приложений, которую я пропускаю?

Редактировать:

Я нашел решение для тестирования команд здесь: http://www.ricardclau.com/2013/02/testing-symfony2-commands-mocking-the-di-container-with-mockery /

Оказалось, что ошибка возникла при ContainerAwareCommand попытке создать новый контейнер, который, очевидно, не будет работать в простой тестовой среде. Я решил проблему, издеваясь над контейнером и вводя его в команду вручную следующим образом:

 use SymfonyComponentConsoleApplication;
use SymfonyComponentConsoleTesterCommandTester;

class MyCommandTest extends PHPUnit_Framework_TestCase {

    public function testExecute() {
        $application = new Application();
        $application->add(new MyCommand());

        $command = $application->find('my:command');
        $command->setContainer($this->getMockContainer()); // <= This avoids ContainerAwareCommand creating a 'real' container in a test env
        $commandTester = new CommandTester($command);
        $commandTester->execute(array('command' => $command->getName()));

        print $commandTester->getDisplay();

        $this->assertRegExp('/.../', $commandTester->getDisplay());
    }

    protected function getMockContainer() {
        // Mock the container and everything you'll need here
        $mockDoctrine = $this->getMock('SymfonyBridgeDoctrineRegistryInterface');
        $mockDoctrine->...;

        $mockContainer = $this->getMock('SymfonyComponentDependencyInjectionContainer');
        $mockContainer->expects($this->once())
                      ->method('get')
                      ->with('doctrine')
                      ->willReturn($mockDoctrine);
        return $mockContainer;
    }
}
  

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

Комментарии:

1. Я на самом деле не эксперт (не слишком много времени для экспериментов и слишком много работы), но я думаю, что вам нужно только подмножество зависимостей, таких как framework-bundle, console, http-kernel для настройки и запуска ваших тестов.

2. Возможно, ваша правка должна быть ответом… В любом случае, хорошая отправная точка. Спасибо!

Ответ №1:

Этот вопрос довольно старый, но я только что наткнулся на него.

Пакеты — это специфичный для Symfony способ совместного использования целых библиотек, включая. их соответствующая конфигурация контейнера для внедрения зависимостей.

Поэтому пакеты зависят от ядра Symfony, и если один пакет зависит от другого пакета, вы создаете тяжелые зависимости, что эффективно предотвращает модульное тестирование: чтобы протестировать модуль (класс) в пакете A, вам понадобится пакет B плюс ядро Symfony.

Вы все еще можете протестировать, но результирующие тесты являются приемочными / интеграционными тестами, а не модульными тестами. Они не подходят для разработки на основе тестирования, медленные и хрупкие, как вы уже заметили.

Обновить

Я только что написал сообщение в блоге об этом: https://lastzero.net/2015/11/dependent-symfony-2-bundles-and-testability /