如何使用 gmock 模拟修改 C++ 类中的私有变量的成员函数?

Posted

技术标签:

【中文标题】如何使用 gmock 模拟修改 C++ 类中的私有变量的成员函数?【英文标题】:How to mock member functions that modify private variables in a C++ class, using gmock? 【发布时间】:2019-11-18 15:32:07 【问题描述】:

我正在努力解决使用 gmock 进行模拟的问题。下面的简化示例描述了它。我在一个类中有公共成员函数,既不返回任何值,也不接受任何输入。它们只更改类中的一些私有变量。还有第三种方法使用这两种方法的效果来计算一些东西(比如,p),然后再将结果吐出给外界。我需要知道如何正确模拟update_a()update_b()。在某种程度上,我可以嘲笑他们。但我只是不知道如何将一些“动作”与其模拟版本相关联,以便通过调用它们我可以对私有变量产生一些影响。这是我目前所拥有的:

class MyClass 

  private:
  int a,
  int b,
  int p;

  public:

  MyClass() : a, b, p 

  void update_a() 
     a += 2;
  

  void update_b() 
     b += 5;
  

  int calculate_p() 
       update_a();
       update_b();
       p = a * 100 + b * 50; // Just some random math making use of a and b.
       return p;
  

class MockMyClass :public MyClass 

public:
  MOCK_METHOD(void, update_a, (), (override));
  MOCK_METHOD(void, update_b, (), (override));
  int deletegate_to_real() 
    return MyClass::calculate_p();
  


TEST(CalculatingP_Test, otherMemberFunctionsInvoked) 

    MockMyClass mockob;
    EXPECT_CALL(mockOb, update_a()).Times(1);
    EXPECT_CALL(mockOb, update_b()).Times(1);

    mockOb.delegate_to_real();

测试通过,因为测试只检查是否调用了 update_a()update_b() 的模拟版本。但是,我无法获得update_a()update_b() 的模拟版本来执行可以直接修改ab 的操作。将private 说明符更改为protected 是我能想到的一种方法。但这不会影响设计吗?

【问题讨论】:

friend testing/mock classes 也是另一种选择。 你为什么需要它?您的被测单元调用了这些方法,是的!这就是测试类测试的重点。对MyClass 的测试以及update_a()update_b() 是否做预期的事情将单独编写(没有MockMyClass @Yksisarvinen:是的,你说得有道理。在不使用 MockMyClass 的情况下,应该对 update_a() 和 update_b() 进行单独的测试。但是,我有一个计算_p() 的测试用例,它需要假设 a = 20000 和 b = 20000。我不允许向当前类引入任何新方法,如 set_a、set_b。我也不想运行循环,只是为了将 a 和 b 的值提高到那么高。所以,我需要一些嘲笑。 我将尝试使用受保护的而不是私有的,看看这是否符合我的意图。 【参考方案1】:

您可以通过 DIP 走得更远:

struct IVarAB

    virtual ~IVarAB() = default;
    virtual void update_a() = 0;
    virtual void update_b() = 0;
    virtual int get_a() = 0;
    virtual int get_b() = 0;
;


class VarAB : public IVarAB

    int a = 0;
    int b = 0;
public:
    void update_a() override  a += 2; 
    void update_b() override  b += 5; 
    int get_a() override  return a; 
    int get_b() override  return b; 
;

class MyClass 
private:
  std::unique_ptr<IVarAB> varAB;
  int p = 0;

public:
  MyClass() : MyClass(std::make_unique<VarAB>())

  explicit MyClass(std::unique_ptr<IVarAB> varAB) : varABstd::move(varAB) 

  void update_a()  varAB->update_a(); 
  void update_b()  varAB->update_b(); 

  int calculate_p() 
       update_a();
       update_b();
       p = varAB->get_a() * 100
         + varAB->get_b() * 50; // Just some random math making use of a and b.
       return p;
  
;

然后您的模拟可以为ab 定义返回值。

【讨论】:

我了解您在此处放置的设计,但这需要我对当前设计进行重大更改,这是我不被允许的。【参考方案2】:

决定我可以继续将“私人”替换为“受保护”。这解决了我所有的问题。

class MockMyClass :public MyClass 

public:
  MOCK_METHOD(void, update_a, (), (override));
  MOCK_METHOD(void, update_b, (), (override));
  void set_dummy_a(int arg_a) a = arg_a;
  void set_dummy_b(int arg_b) b = arg_b;
  int deletegate_to_real() 
    return MyClass::calculate_p();
  


TEST(CalculatingP_Test, otherMemberFunctionsInvoked) 

    MockMyClass mockob;
    EXPECT_CALL(mockOb, update_a()).Times(1);
    EXPECT_CALL(mockOb, update_b()).Times(1);

    mockOb.delegate_to_real();


TEST(CalculatingP_Test, shouldCalculateP_basedon_a_and_b) 

    MockMyClass mockob;
    EXPECT_CALL(mockob, update_a()).WillRepeatedly([&mockob]() 
    mockob.set_dummy_a(20000););
    EXPECT_CALL(mockob, update_b()).WillRepeatedly([&mockob]() 
    mockob.set_dummy_b(20000););
    int expected 3000000;
    EXPECT_EQ(expected, mockob.delegate_to_real());

【讨论】:

以上是关于如何使用 gmock 模拟修改 C++ 类中的私有变量的成员函数?的主要内容,如果未能解决你的问题,请参考以下文章

gTest&gMock learning

如何防止修改类中的私有字段?

在 C++ 中的类中初始化与公共和私有相同的函数:它是如何工作的?

如何使用 GMock 模拟 OpenCV 相机,或者如何使用带有 GTest 的相机测试方法?

在仅拿到头文件的情况下,如何修改类中的私有成员值?

gmock 如何指定不应该调用其他模拟方法?