Параллельное тестирование PHPUnit в интеграционных тестах

поскольку время, необходимое для запуска полного PHPUnit suite, увеличивается, наша команда начинает задаваться вопросом, есть ли возможность запустить модульные тесты параллельно. Недавно я прочитал статью о Paraunit, также Себастьян Бергман написал, что он добавит параллелизм в PHPUnit 3.7.

но остается проблема с интеграционными тестами, или, в более общем плане, тесты, которые взаимодействуют с БД. Для обеспечения согласованности необходимо сбросить testDB и загрузить приспособления после каждого теста. Но в параллельных тестах есть проблема с условиями гонки, потому что все процессы используют один и тот же DB.

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

в своей команде мы используем MongoDB, поэтому одним из решений было бы программно создать файл конфигурации для каждого процесса PHPUnit с сгенерированным именем БД (для этого процесса) и в setUp() метод мы могли бы клонировать основной TestDb в этот временный. Но прежде чем мы начнем реализовывать этот подход, я хотел бы попросить ваши идеи по поводу этой темы.

3 ответов


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

на высшем уровне, совет: избегайте тестирования с базой данных, где это возможно. Абстрактные все взаимодействия с базой данных, а затем издеваться над этим классом. Но вы уже отметили, что ваш вопрос касается интеграционных тестов, где это невозможно.

при использовании PDO, я вообще используйте sqlite:: memory: каждый тест получает свою собственную базу данных. Он является анонимным и автоматически очищается, когда тест заканчивается. (Но я отметил некоторые проблемы с этим, когда вы реальное приложение не использует sqlite:предложения, чтобы избежать DB deps при использовании в памяти SQLite DB для ускорения модульных тестов )

при использовании базы данных, которая не имеет выбора в памяти, создайте базу данных со случайным именем. Если распараллеливание на на PHPUnit уровне, довольно грубая, вы можете использовать процесс pid. Но это не имеет реальных преимуществ перед случайным именем. (Я знаю, что PHP однопоточный, но, возможно, в будущем у нас будет пользовательский модуль phpUnit, который использует потоки для параллельного запуска тестов; мы также можем быть готовы к этому.)

Если у вас есть книга тестовых шаблонов xUnit, Глава 13 посвящена тестированию баз данных (относительно короткая). Главы 8 и 9 о переходных и постоянных приспособлениях также полезны. И, конечно же, большая часть книги посвящена абстракции слои, чтобы сделать издевательство проще : -)


но остается проблема с интеграционными тестами, или, более как правило, тесты, которые взаимодействуют с БД. Ради последовательности, testDB должен быть переустановлен и приспособления нагруженные после каждого испытания. Но в параллельных тестах есть проблема с условиями гонки, потому что все процессы используют одну и ту же БД.

так, чтобы иметь возможность запускать интеграционные тесты параллельно, мы должны назначить собственная база данных для каждого процесса. Я хотел бы спросить, есть ли у кого-то мысли о том, как эту проблему можно решить. Может, уже есть реализованные решения этой проблемы в другой реализации xUnit.

вы можете избежать конфликтов интеграционных тестов 2 способами:

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

Ofc. вы можете объединить эти 2 решения. Я не знаю о любом PHPUnit test runner, который поддерживает любой из этих подходов, поэтому я думаю, что вы должны написать свой собственный Test runner для ускорения процесса... Кстати, вы все еще можете группировать интеграционные тесты и запускать только несколько из них сразу, если вы используете их по разработке...

имейте в виду, что те же конфликты могут вызвать проблемы параллелизма при большой загрузке в PHP. Например, если вы заблокируете 2 файла в обратном порядке под действием 2 отдельных контроллера, ваше приложение может закончиться в тупик... Я ищу способ проверить проблемы параллелизма в PHP, но пока не повезло. В настоящее время у меня нет времени писать собственное решение, и я не уверен, что смогу с ним справиться, это довольно сложно... : S


существует также Эта удивительная библиотека (быстрый) для параллельного выполнения тестов. Он оптимизирован для функциональных / интеграционных тестов, что позволяет легко работать с N базами данных параллельно.

наша старая кодовая база работает через 30 минут, теперь через 7 минут с 4 процессорами.

особенности

  • функциональные тесты могут использовать базу данных на процессор, используя переменная окружения.
  • тесты рандомизированы по умолчанию.
  • не связан с PhpUnit вы можете запустить любую команду.
  • разработан в PHP без зависимостей.
  • в качестве ввода вы можете использовать phpunit.XML.dist файл или использовать канал.
  • включает расширение Behat, чтобы легко передавать сценарии в быстрый.
  • увеличить многословие с опцией-V.

использование

find tests/ -name "*Test.php" | ./bin/fastest "bin/phpunit -c app {};"