Nerdy tidbits from my life as a software engineer

Thursday, February 26, 2009

Bypassing Constructors With Mock Objects

I was working on a class tonight where I wanted to put some initialization logic in the constructor.  But that logic was not something I wanted invoked in my unit tests.  It was creating a new thread, and I didn’t want the thread actually created within my tests because I wanted to isolate the creation and destruction logic of the thread in one place instead of having lots of unrelated tests validate it as well.

So how do I test this?  Well one option is to take the logic out of the constructor and move it into another method.  Then I can use a partial mock and mock the call.  But that isn’t really preferable in most cases, because now I’m forcing somebody to make an additional method call if they want to use my object properly.  So I’m really not encapsulating behavior very well.  I didn’t like that idea.

And then it occurred to me that there’s really a very simple solution to this problem, and that is to define a protected constructor which does not call the things you want to be avoided in your tests.  Then, you can use a partial mock that calls the protected method instead of the public one, and viola – the real, publically exposed constructor is not called in the tests, but is called in the real world.

So just to illustrate how this works:

public class TestMe
{
    public TestMe()
    {
        // Called by everybody else
    }

    protected TestMe()
    {
        // Called from mock objects
    }
}

I had to make a few minor changes in my mock framework to get this working (just search for NonPublic constructors as well as Public ones).  But I think the results are encouraging.  What I like about this is that it doesn’t expose behavior to anybody, and since only subclasses can call the protected constructor, there’s no real loss of encapsulation.  Sure, somebody else could come along and subclass TestMe, calling the protected constructor instead of the public one.  But  that’s their problem.  If they break the behavior of the parent class in the subclass, well, they’re not doing a very good job of writing object orientated code.

1 comments:

Anonymous said...

Doesn't this sort of violate the idea that you are testing the publlic interface to your class? I imagine in my environment that someone will come along and change the public constructor in such a way that makes the entire app blow up (ok, you get it)... but the test still runs fine.
Maybe I still am hazy as to when the test should make up for crappy development and when the developers just need hung :)