views:

713

answers:

2

Does anyone have any suggestions for a best practice or preferred way of rolling back database transactions made from an integration test framework such as Selenium?

Here is our current situation: We have a .net web project with a number of unit tests which work fine in our unit test environment - each test inherits a parent class which opens a transaction in the [SetUp], and rolls back the transaction in the [TearDown]. After each test, our unit test database is restored back to the original state.

However, things change once we get to our integration environment. Our continuous integration server automatically compiles our commits and pushes them out to a test server, so that the server always runs on the most up to date code. We've also setup a Selenium instance to automate user interaction with the site. The selenium tests basically communicate with an existing Selenium server, and tell the server things like, "Launch a browser and go to http://testsite/TestPage.aspx - enter text 'abc' into form field with id 'def' - assert new page contains text 'xyz'"

Each test is run in a similar manner to our vanilla unit tests, but with an important exception: any changes made by Selenium are done in a completely different thread/application, and therefore we can't (I *think we can't, at least) roll them back in the test teardown.

We've yet to come to a good solution for this. Right now we're at a point where we're using a SqlCommand to execute a sql statement to backup the database, then at the end of the test, we're setting the database to single user, dropping the current db, and restoring the old copy - this is less than ideal, because that effectively kills the application that was attached to the DB, and requires us to yet again re-initialize the app.

Is this a problem that has been solved before? Any advice would be awesome.

Thanks!

+1  A: 

We are running a drop/create-table script before every test. This is quite fast and ensures that nothing is left from previous tests.

PS: We are using NHibernate, which creates this script on the fly and run the test on Sqlite in memory, it's lightspeed. But if we switch to SqlServer it's still quite fast.

Stefan Steinegger
Thanks Stefan,This seems to be the best solution - we've resorted to just truncating tables and re-loading the fixtures after every test, which isn't really *that* taxing, and it seems like it's working well.Thanks again!
mjd79
Truncating on oracle is quite fast, because you can't rollback this operation. The scripts are easy in our situation, the scripts are already available, we don't have to maintain something else.
Stefan Steinegger
@Stefan - Is this script run before every test method or test case? I would assume every test method.... Also how is this script run? Do you have a service API in the back end?
HDave
It's run before every test method. Its run by NHibernates SchemaExport class which is pretty easy to use. It creates the tables based on the mapping files.
Stefan Steinegger
+1  A: 

It's a tough problem and the solution is typically unique for every app. Until the major frameworks adopt a "recommended approach", this will continue to be a pain.

My best recommendation: plan for this usage at the start of your app. Include APIs that clean up after the DB is reset from underneath the app (ie: reset caches).

Patrick Lightbody