Объединение JBehave с SpringJUnit4ClassRunner для включения отката транзакции

Суть:

Как я могу автоматически откатить свою гибернационную транзакцию в тесте JUnit с помощью JBehave?

Проблема, похоже, в том, что JBehave хочет SpringAnnotatedEmbedderRunner, но для аннотирования теста как @Transactional требуется SpringJUnit4ClassRunner.

Я пытался найти документацию о том, как реализовать откат с помощью SpringAnnotatedEmbedderRunner или заставить JBehave работать с помощью SpringJUnit4ClassRunner, но мне не удалось заставить работать ни то, ни другое.

У кого-нибудь есть (желательно простая) установка, которая запускает истории JBehave с Spring и Hibernate и автоматическим откатом транзакций?



Дополнительная информация о моих настройках:

Работа JBehave с Spring, но без автоматического отката:

@RunWith(SpringAnnotatedEmbedderRunner.class)
@Configure(parameterConverters = ParameterConverters.EnumConverter.class)
@UsingEmbedder(embedder = Embedder.class, generateViewAfterStories = true, ignoreFailureInStories = false, ignoreFailureInView = false)
@UsingSpring(resources = { "file:src/main/webapp/WEB-INF/test-context.xml" })
@UsingSteps
@Transactional // << won't work
@TransactionConfiguration(...) // << won't work
// both require the SpringJUnit4ClassRunner 

public class DwStoryTests extends JUnitStories {

    protected List<String> storyPaths() {

        String searchInDirectory = CodeLocations.codeLocationFromPath("src/test/resources").getFile();
        return new StoryFinder().findPaths(searchInDirectory, Arrays.asList("**/*.story"), null);
    }

}

В моих тестовых шагах я могу @Inject все красиво:

@Component
@Transactional // << won't work
public class PersonServiceSteps extends AbstractSmockServerTest {

    @Inject
    private DatabaseSetupHelper databaseSetupHelper;

    @Inject
    private PersonProvider personProvider;

    @Given("a database in default state")
    public void setupDatabase() throws SecurityException {
        databaseSetupHelper.createTypes();
        databaseSetupHelper.createPermission();
    }

    @When("the service $service is called with message $message")
    public void callServiceWithMessage(String service, String message) {
        sendRequestTo("/personService", withMessage("requestPersonSave.xml")).andExpect(noFault());
    }

    @Then("there should be a new person in the database")
    public void assertNewPersonInDatabase() {
        Assert.assertEquals("Service did not save person: ", personProvider.count(), 1);
    }

(да, все методы databaseSetupHelper являются транзакционными)

PersonProvider — это, по сути, оболочка вокруг org.springframework.data.jpa.repository.support.SimpleJpaRepository. Таким образом, есть доступ к entityManager, но получение контроля над транзакциями (с началом/откатом) не сработало, я думаю, из-за всех @Transactional, которые выполняются под капотом внутри этого вспомогательного класса.

Также я читал, что JBehave работает в другом контексте?сеансе?что-то? что вызывает потерю контроля над транзакцией, запущенной тестом? Довольно запутанная вещь..


изменить:

Отредактируйте вышеизложенное, перефразировав пост, чтобы отразить мои текущие знания, и сократив все это, чтобы вопрос стал более очевидным, а установка менее навязчивой.


person Pete    schedule 14.05.2012    source источник


Ответы (3)


Я думаю, вы можете пропустить SpringAnnotatedEmbedderRunner и предоставить необходимую конфигурацию JBehave самостоятельно. Например, вместо

@UsingEmbedder(embedder = Embedder.class, generateViewAfterStories = true, ignoreFailureInStories = false, ignoreFailureInView = false)

ты можешь сделать

configuredEmbedder()
.embedderControls()
.doGenerateViewAfterStories(true)
.doIgnoreFailureInStories(false)
.doIgnoreFailureInView(false);

Кроме того: почему вы хотите откатить транзакцию? Обычно вы используете JBehave для приемочных тестов, которые выполняются в рабочей среде. Например, вы сначала настраиваете некоторые данные в базе данных, получаете к ним доступ через браузер/Selenium и проверяете результаты. Чтобы это работало, транзакция БД должна быть зафиксирована. Нужно ли вам очищать вручную после ваших тестов, что вы можете сделать в аннотированных методах @AfterStories или @AfterScenario.

person AndreasEK    schedule 22.06.2012
comment
Хм... Похоже, я мог бы попробовать. Спасибо, проверю на следующей неделе. Наши приемочные тесты не будут выполняться против развернутого приложения, мы оставляем это для сквозных тестов. Наши приемочные тесты будут выполняться непосредственно для модели предметной области, включая чистую базу данных, для которой мы хотим выполнить автоматический откат. - person Pete; 22.06.2012

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

@Component
public class MySteps
{
    @Autowired
    MyDao myDao;

    @Autowired
    PlatformTransactionManager transactionManager;

    TransactionStatus transaction;

    @BeforeScenario
    public void beforeScenario() {
        transaction = transactionManager.getTransaction(new DefaultTransactionDefinition());
    }

    @AfterScenario
    public void afterScenario() {
        if (transaction != null)
            transactionManager.rollback(transaction);
    }

    @Given("...")
    public void persistSomething() {
        myDao.persist(new Foo());
    }
}
person ievgen    schedule 09.07.2014

Я не знаком с JBehave, но, похоже, вы ищете эту аннотацию.

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true).

Вы также можете установить для defaultRollback значение true в вашем testContext.

person arcdrag    schedule 14.05.2012
comment
Нет, это не сработает. Это аннотация SpringJUnit4ClassRunner, которая будет игнорироваться SpringAnnotatedEmbedderRunner JBehave. - person Pete; 15.05.2012