Unit testing and stubbing singletons

May 4, 2010 by · Leave a Comment
Filed under: Development, Projects 

I got a bit curious about stubbing Singletons for testing during the weekend as well. We often find ourselves needing to test large codebases at work, and in the current project I’m in, we do complete end to end signal flow tests, but people are finally realizing that this will simply not do. For this reason, we’re doing a lot of work to try to split the entire project up into manageable chunks. One of the main problems has been the incessant use of singletons. A simply half-way-there to doing full out interfaces is to simply make all public function calls virtual and then create a stub class of the singleton saving the message or whatever passed on, into a variable which can be grabbed and tested from the actual unit test.

A sample of the general idea below:

#include 

class A
{
public:
    static A *instance()
    {
        std::cout << "A::instance()" << std::endl;
        if (!s_instance)
            s_instance = new A;
        return s_instance;
    };

    A()
    {
        std::cout << "A::A()" << std::endl;
    };
    // Virtual makes the difference
    virtual void send(int i)
    {
        std::cout << "A::send()" << std::endl;
        // Blah blah, send i or something
    };
    static A *s_instance;
private:
};

class stub_A: public A
{
public:
    static stub_A *instance()
    {
        std::cout << "stub_A::instance()" << std::endl;
        if (!s_instance)
        {
            s_instance = new stub_A;
            A::s_instance = s_instance;
        }
        return s_instance;
    };

    stub_A()
    {
        std::cout << "stub_A::stub_A()" << std::endl;
    };

    void send(int i)
    {
        std::cout << "stub_A::send()" << std::endl;
        y = i;
    };

    int getMessage()
    {
        return y;
    };
private:
    int y;
    static stub_A *s_instance;
};

A *A::s_instance = 0;
stub_A *stub_A::s_instance = 0;


int main(int argc, char **argv)
{
    stub_A::instance()->send(5);
    std::cout << "stub_A::instance()->getMessage() == " << 
        stub_A::instance()->getMessage() << std::endl;

    A::instance()->send(7);
    std::cout << "stub_A::instance()->getMessage() == " << 
        stub_A::instance()->getMessage() << std::endl;
}