Saturday, January 5, 2008

Unit testing pattern

In this article I'm going to present a pattern I've developed for creating xUnit-tests in .Net, code samples will be in C# but the pattern is equally well suited for VB.Net or any other .Net-language that has preprocessor #if-equivalents. The main benefits of using this pattern is that your tests will be an integral part of the code under test and that it gives you access to all non-public members of the tested class making it easier to use test doubles (stubs, mocks, etc.) while also removing any requirements from tests on the public interface of a class.

Common practice

I've found that the most common practice when creating xUnit-tests for a project is to create another project with the ".Tests" suffix. For example if I create the project Foo.Bar, I'd also create a project Foo.Bar.Tests where I'd put all my test code for the Foo.Bar project.

twoprojects

This is the way I used to do it and it's certainly not a bad way, but it has some drawbacks, first of all it's a bit cumbersome having to manage two separate projects, when adding a class in the tested project one must also be added in the test project, perhaps the test classes should be in namespaces corresponding to the namespaces of the tested classes and so forth. Also, the way I see it tests should be an integral part of the code it tests. You shouldn't be able to get your hands on a piece of code and not at the same times get the tests for that code.

Another drawback is when using stubs, mocks or other test doubles there must be a way to have the tested object used the double-object instead of a production environment counterpart. Oftentimes this leads to adding constructors or properties to classes in order to make them testable that have no use outside testing and could even break encapsulation.

There's also a third issue that is a drawback or something positive, depending on how you look at it. When put in a separate project the test code can only test public members. There are different schools regarding this, there are those that say that tests should only test the public interface of a class and there are those that say that every member should be tested. I'm leaning more towards the first category. I think that tests should focus on the public interface of the class, or at least the non-private interface, but it can't be bad to have the option to test private members as well. (I'd also like to point out that I am aware that there are ways to get around this to enable test of members with a more narrow scope, but they are workarounds).

The way I do it

One way to overcome all of these issues is putting the tests in an inner/nested class of the tested class:

public class Foo
{
    public Foo()
    { 
        // Default constructor...
    }

    private Foo(object parameter)
    { 
        // Test only constructor..
    }

    private int Add(int a, int b)
    {
        return a + b;
    }

    [TestFixture]
    public class FooTests
    {
        [Test]
        public void Add_TwoValues_ReturnSum()
        {
            object mock = new object();
            Foo f = new Foo(mock);
            Assert.AreEqual(3, f.Add(1, 2));
        }
    }
}

As you see this makes our test an integral part of the tested code, and it lets us access all non-public members of the tested class so any constructors used for tests only could be declared private and not affect the classes interface.

But clearly this is not a good idea at all, our production code will now contain a lot of test code that simply shouldn't be there, but wait, there's a way to fix this, and it's simple. Let's use the pre-processor if-statement:

public class Foo
{
    public Foo()
    { 
        // Default constructor...
    }

    private int Add(int a, int b)
    {
        return a + b;
    }

#if DEBUG
    [TestFixture]
    public class FooTests
    {
        [Test]
        public void Add_TwoValues_ReturnSum()
        {
            object mock = new object();
            Foo f = new Foo(mock);
            Assert.AreEqual(3, f.Add(1, 2));
        }
    }

    private Foo(object parameter)
    { 
        // Test only constructor..
    }
#endif
}

Now the test code will only be compiled into the assembly when the DEBUG-flag is set, that is when the assembly is compiled with the Debug-configuration.

Debug

Any test-only constructors, properties or other members could be included within this #if-statement to so that they are only included when doing a debug build. Now I think we have a pretty good model, however there is some remaining issues.

The first issue is a minor one, we now have to have a reference to our unit-testing framework of choice in our production code, this is really minor though, since it'll never be used outside of the tests and those are only included in debug builds so when compiling a release build the only thing that will happen is that the referenced dll will be copied to the output directory, it's safe to remove it. A very simple fix is to edit the project file which is easy enough if you know your way around MSBuild, set a conditional attribute on the reference so that it's only included in debug-builds. Of course this goes for any references that's needed by test code only.

The second issue is that our production code is somewhat cluttered with test code, and I simply don't like the way it looks! But wait, 'cause now is where the real beauty of it all will reveal itself... Partial classes! Partial classes were new in the .net-framework 2.0 and is primarily a way to make designer-generated code not interfere with user code (and possibly overwrite it).

So, let's add another code file called Foo.Tests.cs to our project and in that file let's put all our test code, what we'll end up with is these two files:

Foo.cs
using System;

namespace Foo.Bar
{
    public partial class Foo
    {
        public Foo()
        { 
            // Default constructor...
        }

        private int Add(int a, int b)
        {
            return a + b;
        }
    }
}
Foo.Tests.cs
#if DEBUG
using System;
using NUnit.Framework;

namespace Foo.Bar
{
    public partial class Foo
    {
        private Foo(object parameter)
        {
            // Test only constructor..
        }


        [TestFixture]
        public class FooTests
        {
            [Test]
            public void Add_TwoValues_ReturnSum()
            {
                object mock = new object();
                Foo f = new Foo(mock);
                Assert.AreEqual(3, f.Add(1, 2));
            }
        }

    }
}
#endif

As you see now our tests have no impact on the production code in the Foo.cs file and everything looks perfectly normal (well, there is the partial modifier in the class declaration, but I'll live with that), all test code is in a dedicated file and will never be compiled in to release versions, actually note that even the using directives are inside the #if-statement.

There is one more little trick that you can use if you want the test code truly non intrusive in the project and it is making the test code file depend upon the class code file which will make it collapse nicely under the code file, just like designer files do in Visual Studio.

 Visual Studio displays that test file depends upon code file.

All you have to do to make this work is open the project file in a text (or XML) editor and locate the Compile-element for the test file. Add an xml-element under this element named "DependentUpon" with the value set to the name of the class code file:

<!-- Change this: -->
<Compile Include="Foo.Tests.cs" />
<!-- Into this: -->
<Compile Include="Foo.Tests.cs">
    <DependentUpon>Foo.cs</DependentUpon>
</Compile>

Conclusion

The one problem I've found with this is if the tested class is a generic class the inner class can not be instantiated and the tests can't be run. In most cases the easiest way is to simply move the test class out of the tested class so that it's no longer nested, of course the we can't access private or protected members but in most cases there is no need for that, there is however a way to keep the pattern intact with the nested class even in generic classes and I'll blog about that at some later point.

4 comments:

  1. You have some interesting ideas here. I have thought along those lines myself. Especially to be able to do testing on event handlers for the GUI.

    However, there is one drawback with this approach. You will not be able to test your production code, just you debug code.

    When you build for release you will not have your tests and be able to execute them on the the assemblies.

    This will prevent you from be 100% certain that your production code will passes all your tests.

    ReplyDelete
  2. Very interesting idea, but one thing I don't get in the given example is why we needed to introduce new DI private constructor which accept object when it's value is not used in real code

    Is the intention here to have a poor man dependency injection in default constructor (which would inject the default Foo "production" instance)?

    ReplyDelete
  3. Yes Nikola, that's the idea exactly, I should probably update the examples to illustrate this point more clearly. I'm not a big fan of dependency injection frameworks, I think it makes the components a bit less intuitive to use, but that's my personal point of view.

    ReplyDelete
  4. I don't agree with that haqwin, as long as the SUT doesn't have any Conditional-attributes set on them or pre-processor if-statements then the code won't differ from the production code. Also unit tests are not supposed to test the system in production, they should test units of code and that can be accomplished with this approach. As far as integration tests goes you'd have to use another approach.

    ReplyDelete