Как откат совершает в Behat 3 функциональных теста с Symfony2 и Doctrine?

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

Возможно, теперь с Behat 3 это возможно.

Я знаю, что с PHPUnit я могу достичь чего-то подобного, используя методы startUp и tearDown.

Я попытался запустить и отменить транзакцию, связанную с аннотациями @BeforeScenario и @AfterScenario, но, похоже, что это так, и приложение не использует один и тот же экземпляр диспетчера сущностей.

Некоторые советы по этому поводу?

Спасибо.


UPDATE

Спасибо всем за ваши советы. Вот некоторые новые соображения:

  • ЗАГРУЗКИ FIXTURES: Да, это работает. Я могу запускать приборы до начала тестов, но проблема (моя ошибка, чтобы не упоминать об этом) заключается в том, что для монтажа иногда требуется несколько минут, и до начала тестов ждать 10 или более минут. >

  • BEGIN/ROLLBACK TRANSACTION: он работает тоже или кажется. Я не получаю ошибок, но данные, записанные во время тестов, все еще находятся в моей базе данных, когда они закончились. Я добавил первый в методе tagged @BeforeScenario e последний в методе, отмеченном @AfterScenario

$this->kernel->getContainer()
    ->get('doctrine.orm.entity_manager')
    ->getConnection()
    ->beginTransaction();

$this->kernel->getContainer()
   ->get('doctrine.orm.entity_manager')
   ->getConnection()
   ->rollBack();
  • SAVEPOINT. Я думаю, что именно то, что мне нужно, но мои данные все еще существуют. Я попытался добавить создание точки сохранения в свой метод @BeforeScenario и откат метода @AfterScenario
public function gatherContexts(BeforeScenarioScope $scope) {
    $environment = $scope->getEnvironment();
    $connection = $this->kernel->getContainer()->get('doctrine.orm.entity_manager')->getConnection();
    $connection->beginTransaction();
    $connection->createSavepoint('tests');
}

public function rollback(AfterScenarioScope $scope) {
    $connection = $this->kernel->getContainer()->get('doctrine.orm.entity_manager')->getConnection();
    $connection->rollbackSavepoint('tests');
}

Все эти тесты используются для тестирования моего проекта REST API. После этих соображений я думаю, что Behat и мое приложение не используют один и тот же экземпляр менеджера сущности. Можете ли вы поделиться одним и тем же экземпляром между вашими тестами и вашими проектами во время тестов?

Ответ 1

Если ваш контекст реализует KernelAwareContext, то в аннотированных методах @BeforeScenario и @AfterScenario вы можете сделать

$this->kernel->getContainer()->getDoctrine()->getConnection()->beginTransaction();
$this->kernel->getContainer()->getDoctrine()->getConnection()->rollBack();

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

Вы также можете попробовать $connection->setRollbackOnly(), но имейте в виду, что он будет дико зависеть от вашего базового db. Mysql может автокомментировать в нескольких случаях, если бы вы этого не ожидали.

И, наконец, есть и $connection->createSavepoint('savePointName') для использования с $connection->rollbackSavepoint('savePointName')

Это из моей головы, поэтому может потребоваться некоторые корректировки.

Ответ 2

С помощью метода setUp вы можете начать транзакцию. Вы можете откатить его в методе tearDown, если между двумя вызовами метода нет фиксации.

Очень опасно запускать тесты в производственной базе данных, даже если вы откатываете запросы. Это лучший способ инициализировать тест базы данных с помощью прибора. Если вы не можете это сделать (я так думаю), вы хотите протестировать с данными о производстве. Используйте doctrine:migrations (или doctrine:schema:create), чтобы скопировать схему производственной базы данных в среду разработки и добавить script для копирования данных.

Ответ 3

Я думаю, что схема "dropping" и "create" - это решение, которое вы ищете.

Я использую Behat3 для моего функционального тестирования - я тестирую довольно сложное веб-приложение и API REST. Я использую подготовленные приборы, а также добавляю дополнительные данные во время сценария.

Вы можете настроить контекст Behat для загрузки светильников для каждого (до) сценария - это работает очень хорошо:

class CustomContext implements Context, KernelAwareContext {

    /**
     * @param type ScenarioEvent
     *
     * @BeforeScenario
     */
    public function reloadSchema($event)
    {
        // Note: EntityManager and ClassMetadata is required
        // reload Schema
        $schemaTool = new SchemaTool($entityManager);
        $schemaTool->dropSchema($metadata);
        $schemaTool->createSchema($metadata);
    }

    /**
     * @param type ScenarioEvent
     *
     * @AfterScenario
     */
    public function closeConnections($event)
    {
        // close connection(s)
    }

    // ...

}

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

Я использую следующую конфигурацию для Behat светильников:

Благодаря этому вы можете загружать светильники в сценарии:

Given the fixtures file "dummy.yml" is loaded
Given the fixtures file "dummy.yml" is loaded with the persister "doctrine.orm.entity_manager"
Given the following fixtures files are loaded:
  | fixtures1.yml |
  | fixtures2.yml |

Позвольте мне теперь, если вам нужно больше деталей.