Testing ActiveRecord objects

time to read 11 min | 2030 words

Steve has posted a question about how to test ActiveRecord objects, since they have static methods with no easily visible places to shove a mock implementation.

One of the core ideas of ActiveRecord is that of a Scope. Fairly often you are not aware that you are using it, since it is entirely possible to use it impliciltly. But when you are using SessionScope to allow lazy loading, or TransactionScope to ensure referential integrity, you are using the scope.

In its simplest form, a Scope simply holds a session, the default implementation opens and close a session per database call, SessionScope will hold to the same same session until it is disposed, etc. This allows us to enter mocking into the process, which will hand an NHibernate session to the rest of the code.

Here is the simplest thing that I could think of:

public class MockScope : AbstractScope

{

 

    ISession session;

    public MockScope(ISession session) : base(SessionScopeType.Custom)

    {

        this.session = session;

    }

 

    public override bool IsKeyKnown(object key)

    {

        return true;

    }

 

    public override ISession GetSession(object key)

    {

        return session;

    }

}

This just hold to an external session (and don't dispose of it!) while it is registered. You can use it like this:

[Test]

public void UsingMockedScope()

{

    MockRepository mocks = new MockRepository();

    ISession session = mocks.CreateMock<ISession>();

    Blog mockedBlog = new Blog();

    Expect.Call(session.Load(typeof(Blog), 30)).Return(mockedBlog); ;

    mocks.ReplayAll();

    using (new MockScope(session))

    {

        Blog blogFromDatabase = Blog.Find(30);

        Assert.AreSame(mockedBlog, blogFromDatabase);

    }

    mocks.VerifyAll();

}

Of late, I begun to really like the generic reposioty approach that Steve has in his post. With NHibernate, you write it once, and it is a strongly typed wrapper for all your objects.