http://qs321.pair.com?node_id=417632


in reply to Automated testing of database classes

The problem with testing database stuff is that you need a known state which you can run the tests against.

There are a few ways you can do this. Most of them involve having a reference database with known data.

One way to restore the known state is to begin a transaction at the beginning of the test and roll it back at the end of the test. Any changes you made during the test are undone.

The problem with this approach is that the rollback semantics in most databases break this; begin and commit are nested properly but a rollback rolls back the entire transaction, not just the most deeply nested one.

In one project with no legacy code we could use transaction savepoints to "fake" proper rollbacks of only the innermost nesting level. And that made it possible to use a transaction for restoring the database state in all unit tests. (The 1100+ unit tests was a success factor for that project btw). This was for Sybase T-SQL, but the savepoint stuff works for Oracle as well.

One more generic way of providing a known state is to make a snapshot of the database before running the tests and restore it just before each test.

If you can run SQLite this is just a matter of copying the, often very small, database file.

If it's any other database, see if you can't script something with your database's data loader utility.

During the actual testing, I find Test::DatabaseRow very useful. One thing to be wary of is that you may have two different database connections to the database, and depending on the isolation level and transaction state, one database connection may not see changes made using the other database connection. And depending on the locking scheme and isolation level, the two connections may lock each other.

/J