Monster classes

I think perhaps the most common anti-pattern I run into in legacy code is the monster class. It’s generally full of monster methods. It can be really annoying and tough to test a client of one of these classes even if it’s a polymorphic class. Having to overload each and every function in it even though you’re not going to use it is a real pain in the butt.

The correct way to deal with this is probably to create another interface that includes the functionality you need, and make the monster class inherit it. Then you remap your client to refer only to that new interface. Sometimes though you can’t. You may not have control of this class or perhaps you’re just looking for a place to stop refactoring because if you don’t, you’ll never finish the task you’re on. Another thing you can do is create an adaptor that fails any test when used directly. An example in C++:


struct monster_class
{
   // many, many functions
   virtual void fun1() = 0;
   virtual int fun2() = 0;
};

struct monster_adaptor : monster_class
{
    template < typename T >
    struct fake_call
    {
        static T call(std::string fun)
        {
            throw std::runtime_error(fun + " is not mocked but was called by your test.");
        }
    };
    void fun1() { return fake_call<void>::call(__FUNCTION__); }
    int fun2() { return fake_call<int>::call(__FUNCTION__); }
    // many more...
};

struct monster_mock : monster_adaptor
{
    void fun1() { ++fun1_calls; }

    int fun1_calls;
    monster_mock() : fun1_calls(0) {}
};

// And now we write a test with the mock, expecting fun2 and others never to be called.
// If they are indeed called then we should expect the test framework to toss a fit about 
// our new exception.

It’s not at all clean, but it usually does the trick. You do run into trouble if your test target catches exceptions. Assuming you can see that this happens as you write the test, and you should be able to, this trick still works. It just becomes a little less obvious that something’s not quite right.

This also assumes you’re not using a mock framework like turtle. If you have that at your disposal it would be much, much better to write a mock class for your monster than to go through these steps.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s