我可以使用 google 模拟来检查方法参数而无需提前设置期望吗?

Can I use google mocks to check method parameters without setting an expectation in advance?

我有这样一种情况,我想检查是否使用参数 X 调用了模拟对象方法,但是测试仅在 调用模拟之后才能访问 X,所以我无法预先设置 EXPECT_CALL。

例如

// The class I'm testing.
class Maker
{
    void register(Listener& lis);
    Obj& make()
    {
        // make new Obj o
        // call created(o) on registered Listener  
        // return o
    }
}

class Listener
{
    virtual void created(Obj& o) = 0;
}

// The test
Listener lis;
Maker maker;
maker.register(lis);

Obj& o = maker.make();

// Check that lis was invoked using param o...how?

我可以用 google 模拟来做到这一点吗?使用 google 模拟最优雅/可读的方法是什么?

显然我可以制作自己的 MockListener 来记录调用参数,而不是使用 google 模拟。但我希望 google mocks 会成为一种更具可读性的机制,类似于 EXPECT_CALL.

您可以使用SaveArg<N> 操作来保存调用Listener::created(Obj&) 的参数值,以便您可以将其值与之后maker.make() 返回的值进行比较。

这将要求您为 class Obj 提供相等运算符,即 bool operator==(const Obj&, const Obj&)

您的测试可能如下所示:

class ListenerMock : public Listener
{
public:
    MOCK_METHOD1(created, void(Obj&));
};

TEST(MakerTest, make_registersObject)
{
    ListenerMock lis;
    Maker maker;
    maker.register(lis);

    Obj createdArg;
    EXPECT_CALL(lis, created(_))
        .Times(1)
        .WillOnce(SaveArg<0>(&createdArg));

    Obj& o = maker.make();

    ASSERT_EQ(createdArg, o);
}

我认为答案是“这不是 google 模拟的目的。”

它似乎是为“基于交互的测试”而不是“基于状态的测试”而设计的,如 here:

所解释的

With Google Mock, you can create mocks in C++ easily. And people might be tempted to use them everywhere. Sometimes they work great, and sometimes you may find them, well, a pain to use. So, what's wrong in the latter case?

When you write a test without using mocks, you exercise the code and assert that it returns the correct value or that the system is in an expected state. This is sometimes called "state-based testing".

Mocks are great for what some call "interaction-based" testing: instead of checking the system state at the very end, mock objects verify that they are invoked the right way and report an error as soon as it arises, giving you a handle on the precise context in which the error was triggered. This is often more effective and economical to do than state-based testing.

If you are doing state-based testing and using a test double just to simulate the real object, you are probably better off using a fake. Using a mock in this case causes pain, as it's not a strong point for mocks to perform complex actions. If you experience this and think that mocks suck, you are just not using the right tool for your problem. Or, you might be trying to solve the wrong problem. :-)