As I've mentioned, I'm a big fan of ActiveRecord. I like having all of my data-access related code stored in exactly one place. There's no separate mapping file to maintain, and if I'm really lazy, I can even let ActiveRecord generate the schema for me (yeah, that doesn't really work once you have to worry about migrating databases between schema versions, but there's probably a way around that).
Testing code that depends on my ActiveRecord object model can be complicated. The tests require that the underlying database be in a known, consistent state, and that means that I have to use test setup/tear down methods to initialize the database with the schema and/or wipe out data created by other tests. Worse, it means I have to actually have a database accessible for use in the tests! Since this behavior tends to be the same across my ActiveRecord-dependent test fixtures, I have created a base test fixture and a simple utility class that keeps my real NUnit test fixtures very simple and free of ActiveRecord initialize and cleanup code, and it uses an in-memory database so there's no dependency on an external database. First, the utility class:
Note how the types used by ActiveRecord are listed in order of dependency. This is important because the test fixture will clean up the database by running DeleteAll commands on the types in that order.
Next is our base test fixture class:
There's quite a bit going on here, so let's walk through it. When inherited by a derived class, the TestFixtureSetup and TestSetup mehods will be called by NUnit automatically. The first method will initialize ActiveRecord, configuring it to use a temporary SQLite database, then populating the database with the schema generated by ActiveRecord. Using SQLite means that the database resides entirely in memory, so I don't have to worry about configuring a separate MS SQL database or something like that. The second method is called by NUnit before each test runs, and it uses the ActiveRecordBase<T>.DeleteAll method to clean out any existing data. Reflection is used because DeleteAll is a static, generic method that must be called on the derived type, not the base type, and there's not a way to do that without reflection unless you couple the code to your models.
The setup methods are declared as virtual, so derived test fixtures can override their behavior if needed. Most of the time though, you can just passively take advantage of the functionality like so:
This is the test fixture from yesterday's post, but all its setup logic is now handled by the base class, freeing you up to write simple, clean tests.