One thing I have really gotten into in the past few months is using SQLite for unit tests. This time last year, I was convinced that unit tests should have absolutely 0 to do with databases, but if your application just has a lot of data access code, then using SQLite gives you a much lighter load than using SQL Server or any other out of process database.
1) Create a base class for your unit test fixtures:
[TestFixture]
public class EntityTestBase
{
…
[ActiveRecord("Person")]
public class Person : ActiveRecordBase
public class Tests : EntityTestBase
2) Create a test fixture setup method in the base test class, which can initialize your DAL.
[TestFixtureSetUp]
public virtual void TextFixtureSetup()
InPlaceConfigurationSource source = new InPlaceConfigurationSource();
Hashtable properties = new Hashtable();
properties.Add("hibernate.connection.driver_class", "NHibernate.Driver.SQLiteDriver");
properties.Add("hibernate.dialect", "NHibernate.Dialect.SQLiteDialect");
properties.Add("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("hibernate.connection.connection_string", TEST_CONNECTION_STRING);
source.Add(typeof(ActiveRecordBase), properties);
ActiveRecordStarter.Initialize(System.Reflection.Assembly.GetExecutingAssembly(),
source);
_session = new SessionScope();
}
3) Create a virtual method for creating schema objects for your entity classes. Since I am using ActiveRecord, this is very straightforward.
public virtual void CreateSchema()
ActiveRecordStarter.CreateSchema();
4) Create another virtual method to create test data.
public virtual void LoadTestData()
// derived classes use this chance to put test data in the database
5) Call 3) and 4) from test fixture setup.
CreateSchema();
LoadTestData();
6) In each entity class, override LoadTestData to load any test reference data you want for all your tests.
public override void LoadTestData()
base.LoadTestData();
new Person("FName1", "LName", new DateTime(1941, 9, 7)).Create();
new Person("FName2", "LName", new DateTime(1951, 9, 7)).Create();
new Person("FName3", "LName", new DateTime(1961, 9, 7)).Create();
7) Add a PrepareForTest method to the base test fixture class, which creates the schema and loads any test data for an entity. Other entity test fixtures can use this to express a dependency:
public void PrepareForTest()
8) If you have an entity you want to test that depends on another entity, call its PrepareForTest method in your own LoadTestData override.
new Car.Tests().PrepareForTest();
9) Back in the base test fixture class, clear up your database when done. When things are going bad, and you need to look at the mess, comment this part out:
[TestFixtureTearDown]
public virtual void TestFixtureTearDown()
if (_session != null)
_session.Dispose();
if (File.Exists(@"..\..\SampleData\TestDatabase.db"))
File.Delete(@"..\..\SampleData\TestDatabase.db");
10) Now you have a stateful world in which to do tests.
[Test]
public void Person_ShouldFastenSeatBeltWhenGettingInCar()
Car theCar = Car.FindFirstByMakeModel("Ford", "Pinto");
Person thePerson = Person.FindByName("FName1", "LName");
thePerson.GetIn(theCar);
Seat thePersonsSeat = theCar.GetSeatOf(thePerson);
Assert.IsTrue(thePersonsSeat.Belt.IsFastened);
Most of this article has been about how I setup my unit tests so that they work nicely with SQLite. Microsoft recently announced SQL Server 2005 Anywhere Edition. This edition, similar in spirit to SQLite, can be xcopy deployed, runs in process, yet is likely much more closely related to the database you are ultimately going to be using in a production environment. In the future, I am going to investigate using SQL Server AE for this type of testing scenario. I may update this article after that.
Using in-process database engines for unit testing is a fast painless way to improve your coverage and test things that would otherwise be a lot more work.