eranpeer / FakeIt

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

Spying object in std::vector would result in infinite call stack #64

Open yunjia opened 8 years ago

yunjia commented 8 years ago

Test case is followed, the call to spied method would create the lambda infinitely (on Mac 10.11, Xcode 7.3.1).

Mock purpose is simple, while calling the actual method, still want to verify it's get called.

using namespace fakeit;
using namespace std;
class Dumb
{
public:
    virtual
    void print()
    {
        std::cout << "Dumb" << std::endl;
    }
};

TEST(MockTests, SpyStubbedMethod)
{
    vector<Dumb> dumbs(10);
    Dumb& dumb = dumbs[0];
    Mock<Dumb> spy(dumb);
    auto mock = [&]() -> void
    {
        std::cout << "Spy!" << std::endl;
        return dumb.print();
    };
    When(Method(spy, print)).Do(mock);

    spy.get().print();

    Verify(Method(spy, print));
}

The above test case would result in infinite call inside the lambda (the lambda seems been created infinitely), however, if the dumb is not an object in vector, it won't have any problem, work as expected, like the following case:

TEST(MockTests, SpyStubbedMethod)
{
    Dumb dumb;
    Mock<Dumb> spy(dumb);
    auto mock = [&]() -> void
    {
        std::cout << "Spy!" << std::endl;
        return dumb.print();
    };
    When(Method(spy, print)).Do(mock);

    spy.get().print();

    Verify(Method(spy, print));
}
whschultz commented 8 years ago

I've been running into the same issue, though when I run into it, I'm not using vectors. In fact, I ran into the issue with your posted test that didn't use vectors. The workaround is to be more explicit about the method being called. That is, your test should be changed to this:

TEST(MockTests, SpyStubbedMethod)
{
    vector<Dumb> dumbs(10);
    Dumb& dumb = dumbs[0];
    Mock<Dumb> spy(dumb);
    auto mock = [&]() -> void
    {
        std::cout << "Spy!" << std::endl;
        return dumb.Dumb::print(); // This fixes the recursion
    };
    When(Method(spy, print)).Do(mock);

    spy.get().print();

    Verify(Method(spy, print));
}

Unfortunately, this isn't very polymorphic, as you have to know the exact type of the object being passed in so that the correct function can be called. Being a unit testing framework, though, you should probably know the type of the object, so it may not be a deal-breaker kind of issue.

In my case, I just wanted to verify that the original function was called without wanting to change its behavior in any way. It would be nice if there were a way to call the original function without needing to resort to casts or explicit method calls.

Visual Studio 2015, Windows 7. commit 44f1373

zhanglix commented 7 years ago

Maybe what you need is the Spy() method?

TEST(MockTests, SpyStubbedMethod)
{
    vector<Dumb> dumbs(10);
    Dumb& dumb = dumbs[0];
    Mock<Dumb> spy(dumb);

    Spy(Method(spy, print)); // Use Spy() method instead of When

    spy.get().print();

    Verify(Method(spy, print));
}