Search code examples
c++googlemock

Class changes required for mocking for Unit Test Cases


We have a class that has methods which implements threads:

class ThreadPool
{
//Thread creation and invocation
int Create();
};

Another class that embeds a ThreadPool in it

class Service
{
public:
ThreadPool mThreadPool;
int start();
}

int Service::start()
{
mThreadPoll.Create();
.......
}

Cause of the above design pattern I am unable to mock my Service class.

I am trying to write an interface class to ThreadPool and use it in Service class:

class InterfaceThreadPool
{
virtual int Create () = 0;
};

class ThreadPool : public InterfaceThreadPool
{
int Create () override;
};

My idea is to create an interface class ThreadPoolImpl which I can use it in my Service Class:

class Service : public ThreadPoolImpl  
{
public:
int start();
}
int Service::start()
{
Create(); // as inherited from ThreadPoolImpl  
.......
}

The benefit is that now I can mock my Service class. But I am unable defined ThreadPoolImpl class

class ThreadPoolImpl : public InterfaceThreadPool
{
int Create () override;
}
int ThreadPoolImpl::Create()
{
//how can I call ThreadPool Create
}

Solution

  • I actually disagree with @Jarod42 comments. If you would like to test and mock both your ThreadPool class and Service class, the comfortable way is to design it like that:

    class InterfaceThreadPool
    {
    public:
        virtual ~InterfaceThreadPool() = default;
        virtual int Create () = 0;
    };
    
    class ThreadPool : public InterfaceThreadPool
    {
    public:
        ~ThreadPool() override;
        int Create () override;
    };
    
    class IService
    {
    public:
        virtual ~IService() = default;
        virtual int start() = 0;
    };
    
    class Service: public IService
    {
    public:
        /*
         * InterfaceThreadPool might be passed by raw ptr, reference, smart ptr, whataver you like the most
         */
        Service(InterfaceThreadPool* mThreadPool);
        ~Service() override;
        int start() override { return mThreadPool_->Create(); }
    private:
        InterfaceThreadPool* mThreadPool_;
    };
    

    Then in your production code you use the appropriate implementation of Service along with ThreadPool. In your tests you can use:

    • MockThreadPool (derived from InterfaceThreadPool) to test Service
    • MockThreadPool + MockService (derived from IService) to test some other things that need those two classes
    • MockService + ThreadPool implementation invoked when start function is called (it's not very common, but maybe you can find it useful)