2

I have a class that is subclass of an external class over which I don't have any control. The external class depend on system resources. For example

class MyClass : public ExternalBase // This class is from external framework and framework requires it to derive from this class.
{
    int doSomePrivateThing(int );
public: 

    virtual int DoSomething(int );
    virtual ~MyClass();
}

int MyClass::doSomePrivateThing(int )
{
    // do some private task
}

int MyClass::DoSomething(int n)
{
    // Do MyClass Specific task
    int k = doSomePrivateThing(n);
    return ExternalBase::DoSomething(k); // This function depends on external system resources.
                                         // Probably try to communicate with remote server 
                                         // or attempt access Storage or Display device etc.
}

MyClass::~MyClass()
{}

How can I break the dependency of MyClass and write unit test for MyClass::DoSomething(). Using composition in place of inheritance is not a choice as framework requires classes to be derived from this base class.

I am using C++ and GoogleTest/Mock. But any generalized solution is appreciated.

Thanks in advance.

army007
  • 551
  • 4
  • 20
  • 1
    @SergeyA I can't give up just like that. Can't I do some macro and/or template tricks to break the dependency? I have an idea, but I am not sure if it is good. I will post that as an answer. But I am waiting for others if someone else has a better idea. – army007 May 04 '16 at 17:35
  • My experience is with CppUTest, so the terms might be off. But the best that could be expected is that you check that the MyClass::DoSomething functions as expected up to the external call, at which point you could test that you are passing it what you expect. In CppUTest this is acomplished through mocking, I'm not sure what the GoogleTest equivelent is. – Aumnayan May 04 '16 at 18:08
  • @SergeyA You are right I can't really apply the macro and/or template magic here. I tried to templatize the baseclass so that I can feed a mock to it. But it did not work. – army007 May 04 '16 at 18:41
  • @Aumnayan GoogleTest has mocks. And your idea of expecting external calls from MyClass::DoSomething() seems the only way. That ofcourse implies I need the source code of the external class to know what external calls it would make. And by any chance if it call any static or global function then we are doomed again. – army007 May 04 '16 at 18:41

1 Answers1

2

There are two ways. I call them "a little more correct" way and "very ugly" way.


The "more correct" way:

Enclose external class functions with some additional layer than can be partial mocked.

class MyClass : public ExternalBase // This class is from external framework and framework requires it to derive from this class.
{
    int doSomePrivateThing(int );
public: 
    virtual void BaseDoSomething(int) { return ExternalBase::DoSomething(v); }
    virtual int DoSomething(int v);
    virtual ~MyClass();
};

int MyClass::DoSomething(int n)
{
    // Do MyClass Specific task
    int k = doSomePrivateThing(n);
    return BaseDoSomething(k); 
}

And partial mock in UT in this way:

class TestableMyClass : public MyClass
{
public:
    using MyClass::MyClass;
    MOCK_METHOD1(BaseDoSomething, int(int));
}; 

TEST(A,A)
{
    TestableMyClass objectUnderTest;
    EXPECT_CALL(objectUnderTest, BaseDoSomething(112));

    objectUnderTest.DoSomething(112);
}

When you need to call also the true base class method in your test - use WillOnce(Invoke...) with EXPECT_CALL.


The "very ugly" way:

Provide your own UnitTest implementation of ExternalBase and link it to your test. This "UnitTest" impolementation of ExternalBase should be based on some global Mocks objects.

ExternalBaseMock.hpp:

class ExternalBaseMock 
{
public:
    MOCK_METHOD1(DoSomething, int(int));
};
extern ExternalBaseMock  externalBaseMock;

ExternalBaseMock.cpp:

ExternalBaseMock  externalBaseMock;

int ExternalBase::DoSomething(int n)
{
    return externalBaseMock.DoSomething(n);
}

Then your tests:

#include "ExternalBaseMock.hpp"

TEST(A,A)
{
    MyClass objectUnderTest;
    EXPECT_CALL(externalBaseMock, DoSomething(112));

    objectUnderTest.DoSomething(112);
}
Community
  • 1
  • 1
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
  • Thank you very much. Both of the ways are very effective and it has solved my problem. I like the "ugly way" most. Because I can use conditional compilation and replace the `ExternalBase` class with this fake class. In "more correct way" every base class method (that I want to test) have to have a corresponding method in derived class. @PiotrNycz Is there any particular reason for calling it the "ugly way"? Is there any problem that may arise with this approach? – army007 May 06 '16 at 15:12
  • the problem is its thread unfriendliness and you can have effectively just one object of such "ugly mocked" class. In most cases in UT - they are not a big problems. The more important is that it is a little against philosophy of mocking bla bla bla... Just use it if it is best suited for you needs... – PiotrNycz May 06 '16 at 15:42
  • BTW both problems have workarounds - but it complicates more what you are testing - so probably not big deal – PiotrNycz May 06 '16 at 15:44
  • Yeah for me those are not problem. I am planing to test MFC's `CWnd` derived classes. I don't want to create window as that will require to have a message loop which is problematic in testing. – army007 May 06 '16 at 15:51