views:

728

answers:

6

Hello! I'm writing unit-tests for an app that uses a database, and I'd like to be able to run the app against some sample/test data - but I'm not sure of the best way to setup the initial test data for the tests.

What I'm looking for is a means to run the code-under-test against the same database (or schematically identical) that I currently use while debugging - and before each test, I'd like to ensure that the database is reset to a clean slate prior to inserting the test data.

I realize that using an IRepository pattern would allow me to remove the complexity of testing against an actual database, but I'm not sure that will be possible in my case.

Any suggestions or articles that could point me in the right direction?

Thanks!

--EDIT--

Thanks everyone, those are some great suggestions! I'll probably go the route of mocking my data access layer, combined with some simple set-up classes to generate exactly the data I need per test.

A: 

I don't think there is an easy way to finish this. You just have to create those Pre-Test sql setup scripts and post-test Tear-down scripts. Then you need trigger those scripts for each run. A lot of people suggest SQLLite for unit test setup.

J.W.
SQLLite has many difference from big databases, so no sense to test on it
dynback.com
A: 

Roy Osherove has written an interesting article on this subject using enterprise services.

Darin Dimitrov
A: 

I know you're using C# but in the Java World there's the Spring framework. It allows you to run database minipulations in a transaction and after this transaction, you roll this one back. This means that you operate against a real database without touching the state after the test finishes. Perhaps this could be a hint to further investigation in C#.

Mork0075
FYI - spring is available for .net too - http://www.springframework.net/
Eric Petroelje
What if I need to test, several transaction functions, how I know that they work, if I cant commit?
dynback.com
To dynmack.com: Yes, that's the right point unfortunately.
nightcoder
A: 

I found it best to have my tests go to a different db so I could wipe it clean and put in the data I wanted for the test.

You may want to have the database be something that can be set within the program, then your test can tell the classes to change the database.

James Black
+11  A: 

Here's the general approach I try to use. I conceive of tests at about three or four levels:: unit-tests, interaction tests, integration tests, acceptance tests.

At the unit test level, it's just code. Any database interaction is mocked out, either manually or using one of the popular frameworks, so loading data is not an issue. They run quick, and make sure the objects work as expected. This allows for very quick write-test/write code/run test cycles. The mock objects serve up the data that is needed by each test.

Interaction tests test the interactions of non-trivial class interactions. Again, no database required, it's mocked out.

Now at the integration level, I'm testing integration of components, and that's where real databases, queues, services, yada yada, get thrown in. If I can, I'll use one of the popular in-memory databases, so initialization is not an issue. It always starts off empty, and I use utility classes to scrub the database and load exactly the data I want before each test, so that there's no coupling between the tests.

The problem I've hit using in-memory databases is that they often don't support all the features I need. For example, perhaps I require an outer join, and the in-memory DB doesn't support that. In that case, I'll typically test against a local conventional database such as MySQL, again, scrubbing it before each test. Since the app is deployed to production in a separate environment, that data is untouched by the testing cycle.

Don Branson
What do the scrub classes look like? Do you find the most recent Primary Key ID and delete the associated record?
Robert Harvey
No, actually, it completely removes everything, and loads just what I need for the test.
Don Branson
+2  A: 

The best way I've found to handle this is to use a static test database with known data, and use transactions to ensure that your tests don't change anything.

In your test setup you would start a transaction, and in your test cleanup, you would roll the transaction back. This lets you modify data in your tests but also makes sure everything gets restored to its original state when the test completes.

Eric Petroelje
How do you know that your changes worked if you don't commit the transaction?
Robert Harvey
@Robert - after doing the update (but before doing the rollback), your test would perform whatever checks were necessary to verify that the update occurred correctly. Since the checks are executed in the same transaction as the update, they should see the updates even though they haven't been committed yet.
Eric Petroelje
For your idea, transaction should be in test, not in method that you test.
dynback.com
@dynback.com - yes, that is correct, although if you are using something like TransactionScope both the test and the method itself could have their own transaction handling.
Eric Petroelje