【问题标题】:How to invoke a method on a object passed to a mocked method如何在传递给模拟方法的对象上调用方法
【发布时间】:2016-02-15 21:04:31
【问题描述】:

我对 gmock 的工作方式很陌生。

我有一个带有 addEvent 方法的模拟,它通过指针获取 MyClass 类型的对象。我需要在这个对象上调用 MyClass::makeCall。

class SchedulerMock
{
public:
    MOCK_CONST_METHOD1(addEvent, void(MyClass*));

};

我发现了这个话题: What is the easiest way to invoke a member function on an argument passed to a mocked function?

还有例子:

IFooable* ifooable = new IFooableImpl(...); 
TMockFoo MockFoo;
ON_CALL(MockFoo, Foo(_))
  .WithArg<0>(Invoke(&ifooable,&IFooable::Fooable));

但我不想在测试中创建的对象上调用方法。我想模拟在实际传递给模拟的对象上调用 makeCall 。 因此,我可以将我的模拟注入另一个将创建一些新对象的类,并在我的 schedulerMock 上调用 addEvent ,我希望这个模拟在每次有人在我的模拟上调用 addEvent 时在传递的参数上调用 makeCall 。 希望我说清楚了。

这可能吗?

【问题讨论】:

  • 我对您想要做什么的理解有所了解...如果我误解了您,请通过小例子告诉我。

标签: c++ unit-testing googletest googlemock


【解决方案1】:

您可以定义自定义操作(在命名空间范围内 - 在任何其他函数、测试等之外)。 Action 将有权访问模拟函数调用的参数,在本例中是您要调用 makeCallMyClass *

ACTION(MakeCall)
{
    // arg0 is predefined as 0-th argument passed to the mock function call,
    //  MyClass* in this case
    arg0->makeCall();
}

TEST(...)
{
    // Create mock object and set expectation, and specify to invoke the 
    //  MakeCall Action
    SchedulerMock mock;
    EXPECT_CALL(mock, addEvent(_))
        .WillOnce(MakeCall());

    ...
}

当调用mock.addEvent(my_class_ptr) 时,将使用给定的MyClass * 指针调用MakeCall 操作。

您还可以使用它来将测试中定义的参数传递给操作。例如,如果您的 MyClass::makeCall 方法采用 int 参数,假设您想在第一次和第二次调用该方法时传递两个不同的值:

class MyClass
{
    void makeCall(int);
};

ACTION_P(MakeCall, value)
{
    arg0->makeCall(value);
}

TEST(...)
{
    const int FIRST_VAL = 10;
    const int SECOND_VAL = 20;

    MyClass my_class_obj;
    SchedulerMock mock;
    EXPECT_CALL(mock, addEvent(_))
        .WillOnce(MakeCall(FIRST_VAL))
        .WillOnce(MakeCall(SECOND_VAL));
    ...
}

有关更多详细信息,请参阅 Google 模拟文档:

Google Mock Cheat Sheet - Defining Actions

Google Mock Cookbook - Writing New Actions Quickly

【讨论】:

    【解决方案2】:

    您可以使用另一个调用模拟函数的函数...

    class SchedulerMock
    {
      public:
        //.... etc
        void addEvent(MyClass* c) const
        {
          c->makeCall();
          mockAddEvent(c); //Wholla, test still works and makeCall called. 
        }
    
        MOCK_CONST_METHOD1(mockAddEvent, void(MyClass*));
    };
    

    【讨论】:

    • 嗯,这很有趣。我其实有不同的想法。就像添加一个函数来模拟。 void makeCall(MyClass* p) { p->makeCall();} 然后期望做这样的事情: EXPECT_CALL(scheduler,addEvent(_)).WillOnce(Invoke(&scheduler, &SchedulerMock::makeCall));我也会试试你的方法。谢谢你的提示:)
    • 这很简单,而且很有效。我经常使用该模式返回具有移动语义的对象(如 unique_pointer)。通常我会将 addEvent 设为私有,但您没有与公共 addEvent 的接口(通常,从接口派生用于模拟/存根是一个好主意,直​​到您知道速度是一个问题)。
    • 是的,通常我会模拟一个接口,但在这里我试图模拟一个单例,所以我的 SchedulerMock 不是从真实对象派生的,它只有具有相同签名的方法。然后我需要对使用这个调度器的类进行模板化。我正在使用来自 google coobook 的所谓的高性能模拟:code.google.com/p/googlemock/wiki/… 问题是我不能从这个单例继承事件,因为在他的构造函数中它正在调用另一个单例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-08
    • 1970-01-01
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多