views:

655

answers:

10

Does anyone have some good hints for writing test code for database-backend development where there is a heavy dependency on state?

Specifically, I want to write tests for code that retrieve records from the database, but the answers will depend on the data in the database (which may change over time).

Do people usually make a separate development system with a 'frozen' database so that any given function should always return the exact same result set?

I am quite sure this is not a new issue, so I would be very interested to learn from other people's experience.

Are there good articles out there that discuss this issue of web-based development in general?

I usually write PHP code, but I would expect all of these issues are largely language and framework agnostic.

+3  A: 

You should look into DBUnit, or try to find a PHP equivalent (there must be one out there). You can use it to prepare the database with a specific set of data which represents your test data, and thus each test will no longer depend on the database and some existing state. This way, each test is self contained and will not break during further database usage.

Update: A quick google search showed a DB unit extension for PHPUnit.

Mike Stone
Very interesting, I will definitely have to start looking into that. I don't really properly write unit tests for this reason, and it is a bad practice I need to eliminate.
kaybenleroll
+1  A: 

I have the exact same problem with my work and I find that the best idea is to have a PHP script to re-create the database and then a seperate script where I throw crazy data at it to see if it breaks it.

I have not ever used any Unit testing or suchlike so cannot say if it works or not sorry.

Teifion
+1  A: 

If you can setup the database with a known quantity prior to running the tests and tear down at the end, then you'll know what data you are working with.

Then you can use something like Selenium to easily test from your UI (assuming web-based here, but there are a lot of UI testing tools out there for other UI-flavours) and detect the presence of certain records pulled back from the database.

It's definitely worth setting up either a test version of the database - or make your test scripts populate the database with known data as part of the tests.

davewasthere
+2  A: 

If you're mostly concerned with data layer testing, you might want to check out this book: xUnit Test Patterns: Refactoring Test Code. I was always unsure about it myself, but this book does a great job to help enumerate the concerns like performance, reproducibility, etc.

Chris Farmer
+1  A: 

You could try http://selenium.openqa.org/ it is more for GUI testing rather than a data layer testing application but does record your actions which then can be played back to automate tests across different platforms.

John
+1  A: 

I guess it depends what database you're using, but Red Gate (www.red-gate.com) make a tool called SQL Data Generator. This can be configured to fill your database with sensible looking test data. You can also tell it to always use the same seed in its random number generator so your 'random' data is the same every time.

You can then write your unit tests to make use of this reliable, repeatable data.

As for testing the web side of things, I'm currently looking into Selenium (selenium.openqa.org). This appears to be a cross-browser capable test suite which will help you test functionality. However, as with all of these web site test tools, there's no real way to test how well these things look in all of the browsers without casting a human eye over them!

Chris Roberts
+1  A: 

Here's my strategy (I use JUnit, but I'm sure there's a way to do the equivalent in PHP):

I have a method that runs before all of the Unit Tests for a specific DAO class. It puts the dev database into a known state (adds all test data, etc.). As I run tests, I keep track of any data added to the known state. This data is cleaned up at the end of each test. After all the tests for the class have run, another method removes all the test data in the dev database, leaving it in the state it was in before the tests were run. It's a bit of work to do all this, but I usually write the methods in a DBTestCommon class where all of my DAO test classes can get to them.

Nicholas Trandem
+1  A: 

I would propose to use three databases. One production database, one development database (filled with some meaningful data for each developer) and one testing database (with empty tables and maybe a few rows that are always needed).

A way to test database code is:

  1. Insert a few rows (using SQL) to initialize state
  2. Run the function that you want to test
  3. Compare expected with actual results. Here you could use your normal unit testing framework
  4. Clean up the rows that were changed (so the next run won't see the previous run)

The cleanup could be done in a standard way (of course, only in the testing database) with DELETE * FROM table.

Peter Stuifzand
+1  A: 

In general I agree with Peter but for creating and deleting of test data I wouldn't use SQL directly. I prefer to use some CRUD API that is used in product to create data as similar to production as possible...

Supowski
+2  A: 

We use an in-memory database (hsql : http://hsqldb.org/). Hibernate (http://www.hibernate.org/) makes it easy for us to point our unit tests at the testing db, with the added bonus that they run as quick as lightning..