Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit-Testing: Database set-up for tests

Tags:

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.

like image 859
Charles Avatar asked Apr 24 '09 16:04

Charles


People also ask

Should unit tests connect to database?

Unit tests shouldn't depend on infrastructure 🔗There's no way to test this function without a database connection available at the time of testing. If a new developer clones the project they will need to set up a database before they can successfully run the unit tests.

What is unit test database?

SQL unit testing is a testing method which allows us to test the smallest, atomic programmable part of a database object. SQL unit testing plays a key role in the modern database development cycle because it allows us to test individual parts of the database objects work as expected.


2 Answers

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.

like image 126
Don Branson Avatar answered Oct 18 '22 15:10

Don Branson


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.

like image 39
Eric Petroelje Avatar answered Oct 18 '22 15:10

Eric Petroelje