Isolating Tests From External Influences

time to read 5 min | 823 words

I just posted about semi statics, and now it is finally the post where I explain how I broke the external dependencies in my tests. That was the reason that pushed me to start talking about static in the first place.

I am using NHibernate to handle the data access (naturally), and when I started the project, there was no seperation in the tests from those that needs to touch the database (test that the mapping are working) and those that shouldn't (testing business logic).

I started to feel the pain recently, the tests took a long time to run, and the initial setup overhead was decidely not trivial, so even running a single test took too long. I decided that I really needed to make this seperation to integration tests and unit tests.

The problem was that I had code in both the tests and the business logic that assume that it can pull stuff from the database. I had the architecture I outlined in my previous post, where everything is accessible via the context, and everything is an interface. I did wrote a mocking library, so from there it was mainly going over each test and finding out if it is an integration test or a unit test.  This effort was not trivial, but it certainly paid off. I got a set of tests that run really fast, and I recently had to add another layer that significantly slows the tests. I was able to mock that in about half an hour (to handle all the premutations) and integrate it successuflly.

The integration tests are now much slower, but I don't care that much about their speed at the moment.

The setup for the unit tests is pretty complex right now, since I basically setup the whole environment via Rhino Mocks. All the tests inherits from a common base class that allows me to setup everything once for all the tests.  You can see what I do in this diagram. Just to note, the maximum cyclometic complexity here is 2.

(Image from clipboard).png

By the way, this is the single feature that I absolutely love in Refactor! and CodeRush (where it show you how long a method is).

The whole thing is simply based on code like this:

private void SetupMockObjectInSession(object obj, object key, Type type)

{

    Validation.NotNull(obj, "obj");

    SetupResult.For(_session.Load(type, key)).Return(obj);

    SetupResult.For(_session.Get(type, key)).Return(obj);

}

It gets a little more complex when I need to support complex queries, but it is still easy to grok.

The nice thing about it is that NHibernate is actually a deep infrastructure component in this application, I got a layer or two on top of it, which does all sort of nice things for me (like allowing me to ignore security, or logging, etc), which I am able to test, because I'm mocking the very bottom of the stack.