Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining JBehave with SpringJUnit4ClassRunner to enable transaction rollback

Essence:

How can I auto-rollback my hibernate transaction in a JUnit Test run with JBehave?

The problem seems to be that JBehave wants the SpringAnnotatedEmbedderRunner but annotating a test as @Transactional requires the SpringJUnit4ClassRunner.

I've tried to find some documentation on how to implement either rollback with SpringAnnotatedEmbedderRunner or to make JBehave work using the SpringJUnit4ClassRunner but I couldn't get either to work.

Does anyone have a (preferably simple) setup that runs JBehave storries with Spring and Hibernate and transaction auto-rollback?



Further infos about my setup so far:

Working JBehave with Spring - but not with auto-rollback:

@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);
    }

}

In my test steps I can @Inject everything nicely:

@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);
    }

(yes, the databaseSetupHelper methods are all transactional)

PersonProvider is basicly a wrapper around org.springframework.data.jpa.repository.support.SimpleJpaRepository. So there is access to the entityManager but taking control over the transactions (with begin/rollback) didn't work, I guess because of all the @Transactionals that are done under the hood inside that helper class.

Also I read that JBehave runs in a different context?session?something? which causes loss of controll over the transaction started by the test? Pretty confusing stuff..


edit:

Editet the above rephrasing the post to reflect my current knowledge and shortening the whole thing so that the question becomes more obvious and the setup less obstrusive.

like image 322
Pete Avatar asked May 14 '12 13:05

Pete


3 Answers

I think you can skip the SpringAnnotatedEmbedderRunner and provide the necessary configuration to JBehave yourself. For example instead of

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

you can do

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

Besides: why do you want to rollback the transaction? Typically you are using JBehave for acceptance tests, which run in a production-like environment. For example you first setup some data in the database, access it via Browser/Selenium and check for the results. For that to work the DB transaction has to be committed. Do you need to clean-up manually after your tests, which you can do in @AfterStories or @AfterScenario annotated methods.

like image 80
AndreasEK Avatar answered Nov 06 '22 19:11

AndreasEK


I made it work by controlling transaction scope manually, rolling it back after each scenario. Just follow the official guide how to use Spring with JBehave and then do the trick as shown below.

@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());
    }
}
like image 2
ievgen Avatar answered Nov 06 '22 18:11

ievgen


I'm not familiar with JBehave, but it appears you're searching for this annotation.

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

You could also set defaultRollback to true in your testContext.

like image 1
arcdrag Avatar answered Nov 06 '22 20:11

arcdrag