Подтвердить что ты не робот

Настройка PHPUnit перед запуском первого теста и срыв после запуска последнего теста

Я пытаюсь реализовать утилиту Django для тестирования для php-приложения, используя PHPUnit. По Django, я имею в виду, что отдельный тестовый db создается из основной базы данных перед запуском первого теста, и он упал после запуска последнего теста. Тестовый db необходимо создать только один раз, даже если одновременно запускается много тестовых случаев.

Для этого я принял следующий подход -

Я определил собственный класс тестового набора, чтобы я мог написать код для создания и удаления db в его методах настройки и удаления, а затем использовать этот класс для запуска тестов следующим образом

$ phpunit MyTestSuite

MyTestSuite определяет статический метод с именем suite, где я просто использую glob и добавляю тесты к testuite следующим образом

public static function suite() {
    $suite = new MyTestSuite();

    foreach (glob('./tests/*Test.php') as $tc) {
        require_once $tc;
        $suite->addTestSuite(basename($tc, '.php'));
    }

    return $suite;
}

Все классы Test Case распространяются от подкласса PHPUnit_Framework_TestCase, а методы установки и разборки этого класса обеспечивают загрузку и очистку исходных данных из файлов json fixture.

Теперь как нет. тестов увеличивается, мне нужно запускать только выбранные тесты за раз. Но поскольку я уже загружаю тесты с помощью набора тестов, опция -filter не может использоваться. Это заставляет меня чувствовать, что этот подход, возможно, не был правильным.

Итак, мой вопрос: какой правильный подход сделать что-то перед запуском первого теста и после запуска последнего теста независимо от того, как PHPUnit находит их?

PS: Я не использую PHPUnit_Extensions_Database_TestCase, но моя собственная реализация создания, заполнения и удаления db.

4b9b3361

Ответ 1

Мои две спонтанные идеи, которые не используют "Test Suites". То, что делает, находится внизу.

Тестировщик

Используя PHPUnits test listeners, вы можете сделать

  public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
       if($suite->getName() == "yourDBTests") { // set up db
  }

  public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
       if($suite->getName() == "yourDBTests") { // tear down db
  }

Вы можете определить все ваши тесты БД в testuite в файле конфигурации xml, как показано in the docs

<phpunit>
  <testsuites>
    <testsuite name="db">
      <dir>/tests/db/</dir>
    </testsuite>
    <testsuite name="unit">
      <dir>/tests/unit/</dir>
    </testsuite>
  </testsuites>
</phpunit>

Bootstrap

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

Помещение ссылки на объект в какой-либо глобальной области будет гарантировать, что объект будет только разрушен в конце всех тестов. (Как пояснил @beanland: Использование register_shutdown_function() делает намного больше смысла!)


Использование тестовых наборов:

http://www.phpunit.de/manual/3.2/en/organizing-test-suites.html показывает:

<?php

class MySuite extends PHPUnit_Framework_TestSuite
{
    public static function suite()
    {
        return new MySuite('MyTest');
    }

    protected function setUp()
    {
        print "\nMySuite::setUp()";
    }

    protected function tearDown()
    {
        print "\nMySuite::tearDown()";
    }
}

class MyTest extends PHPUnit_Framework_TestCase
{
    public function testWorks() {
        $this->assertTrue(true);
    }
}

это хорошо работает в PHPUnit 3.6 и будет работать в версии 3.7. Это не в текущих документах, поскольку "классы тестового набора" несколько устарели/обескуражены, но они собираются в течение некоторого времени.


Обратите внимание, что срыв и настройка всего db для каждого тестового примера могут быть весьма полезны для борьбы с межтестовыми зависимостями, но если вы не будете запускать тесты в памяти (например, в памяти SQL), скорость может не стоить он.

Ответ 2

Недавно я столкнулся с чем-то, где мне нужно было решить ту же проблему. Я попробовал Edorian answer с помощью метода __destruct пользовательского класса, но, похоже, он запускался в конце каждого теста, а не по завершении всех тестов.

Вместо использования специального класса в моем файле bootstrap.php я использовал PHP register_shutdown_function для обработки очистки базы данных после завершения всех моих тестов, и казалось, что он отлично работает.

Вот пример того, что у меня было в файле bootstrap.php

register_shutdown_function(function(){
   some_db_cleanup_methods();
});