eranpeer / FakeIt

C++ mocking made easy. A simple yet very expressive, headers only library for c++ mocking.
MIT License
1.26k stars 175 forks source link

Calling production code overrode method #130

Open icaroalvarez opened 6 years ago

icaroalvarez commented 6 years ago

I'm trying to stub a pure virtual method from a derived class. The method is call from another method defined in base class (as pure virtual) and implemented in derived class. Like this:

class A{
public:
    virtual void start() = 0;
};
class B: public A{
public:
    void start() override{
        run();
    };
    virtual void run() = 0;
};

Mock<B> bMock;
Fake(Method(bMock, run));
B &b = bMock.get();
b.start();
Verify(Method(bMock, run)).Once();

Although method start is implemented, when b.start() is executed an unmocked method exception is risen. (Unexpected method invocation: unknown() An unmocked method was invoked. All used virtual methods must be stubbed!)

Would be possible to do that?

alibabashack commented 6 years ago

That's an interesting corner case. Your solution does not work, because Mock<B> bMock does not contain an actual instance of B. (That's why one is using a mocking framework in the first place.) Hence, no implementation of start() is available. As described in the Spying section on the Quickstart page of the wiki https://github.com/eranpeer/FakeIt/wiki/Quickstart#spying you can provide an object to partially retain the implementation. However, this does not work here directly, because B cannot be instantiated, because run() is pure virtual.

As a solution, you can provide a helper class deriving from B, which includes a dummy implementation for run() and then create a mock based on the helper instance:

class A {
public:
    virtual void start() = 0;
};

class B : public A {
public:

    void start() override {
        run();
    };
    virtual void run() = 0;
};

struct BHelper : public B {

    virtual void run() override {
    }
};

BHelper bHelper;
Mock<B> bMock(bHelper);
Fake(Method(bMock, run));
B &b = bMock.get();
b.start();
Verify(Method(bMock, run)).Once();
icaroalvarez commented 6 years ago

@alibabashack Thanks for the reply. The thing is, this does work:

class A{
public:
    void start(){
        run();
    };
    virtual void run() = 0;
};

Mock<A> aMock;
Fake(Method(aMock, run));
A &a = aMock.get();
a.start();
Verify(Method(aMock, run)).Once();

I've finally moved to Trompeloeil and I really like it.

Anyway, thanks again!