简体   繁体   中英

Override non-virtual function for testing purpose

I have a class that I need to mock but the class has non-virtual method that needs to mocked. A simplistic version of my problem is demonstrated below:

#include <iostream>
#include <string>

using namespace std;

class Base{
   public:
    void getNext(){
        cout<<"Base Func"<<endl;
    }
};

class Derived: public Base{
   public:
    void getNext(){
        cout<<"Derived func"<<endl;
    }
};

int main(){
   Base *ptr = new Derived();
   ptr->getNext();
}

The above code will call the Base class's "getNext" function but i want it call somehow the derived class's. Real problem is that I have created a new class whose only public method does some logic and also requires a sequence from database. The class (call it DlSequence) that is fetching the sequence from database is base code of our application (core or product you may call) and I cannot change it. And now I need to test my class using cppunit. So, I have to mock or fake the DlSequence class and override the getNext function but this function is not virtual. Is it possible to mock it ? Or can i bypass this problem with any workaround. I'm not using any mocking framework but I have mockpp installed in my box, I cannot install any other mocking framework. Thanks in advance.

The short answer: no .

If the author of the class did not provide a way to customize the behavior, then it is just not possible.

If you cannot change it yourself, bring up the problem with them that you need a hook.


The long answer:

In terms of C++ there are probably ways to try and hack around it, but it will be both unsafe and brittle. Off the top of my head I could think of injecting a virtual keyword in the base class based on preprocessor hackery or even using LD_PRELOAD to override the function symbol... but honestly, neither is appealing.

Note: if we are talking about testing your code, and you can change your code, then of course you can create a wrapper around this Base thing and make it virtual / template /whatever; I suppose here that you cannot.

In terms of SQL however, you might have a chance, for example by redirecting the API calls or even the network calls to either a mock or a database instance under your control. Not knowing the specifics of your system however I cannot advise any further.

When you're test-driving code that needs to interact with external resources (eg, third-party libraries, I/O, etc.), you generally introduce a seam at which you can mock out the dependency.

This also applies to your situation. If you are unable to modify the code of the collaborator, then it is not much different from a 3rd party library (in that sense). Instead of trying to mock the collaborator directly, identify a seam between your code and the problematic code.

For example:

    #include <iostream>
    #include <string>

    using namespace std;

    class Base{
    public:
        void getNext(){
            cout << "Base Func" << endl;
        }
    };

    class Seam{
    public:
        virtual ~Seam() { }

        virtual void getNext() = 0;
    };

    class MockCollaborator : public Seam{
    public:
        void getNext(){
            cout << "Derived func" << endl;
        }
    };

    class RealCollaborator : public Seam{
    public:
        void getNext(){
            Base base;
            base.getNext();
        }
    };

    int main(){
        Seam* ptr = new MockCollaborator();
        ptr->getNext();
    }

If you can make your class template, you can use something like the following:

class Base {
public:
    void getNext() { cout << "Base Func" << endl; }
};

// Has the same interface of Base
class MockedBase {
public:
    void getNext() { cout << "Derived func" << endl; }
};

And in your class, do something like:

template <typename T> class myClass
{
public:
    void callGetNext() { base.getNext(); }
private:
    T base;
};

And so use myClass<Base> in real code, and myClass<MockedBase> in unittest.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM