c ++中的模拟静态方法

问题描述 投票:1回答:2

我刚刚开始使用googleTest进行单元测试。我遇到一个类的静态方法正在另一类内部调用的情况

class A {
  public:
   static bool retriveJsonData(std::string name, Json::Value& responseJsonData);
}

在其他类中,我正在使用A类retriveJsonData方法。

class B {
   public:
     bool Method1 (std::string name) {
        Json::Value sampleJsonData;
        return A::retriveJsonData(name, sampleJsonData);
 }

模拟A类

class MockA : public A {
  public:
    MOCK_MEHTOD2(retriveJsonData, bool(std::string, Json::Value));

}

现在我必须使用EXPECT_CALL在B类的Method2测试中模拟retriveJsonData。

请帮助我解决如何测试这种情况?

c++11 googletest gmock
2个回答
1
投票

使用A作为类B中的模板参数(请参阅Modern C++ Design

template <class T>
class B {
 public:
  bool Method1 (std::string name) {
     Json::Value sampleJsonData;
     return T::retriveJsonData(name, sampleJsonData);
  }
}

然后在您的测试中使用:

B<MockA> b;

在生产代码中:

B<A> b;

0
投票

Google Mock的模拟类型提供了检查非静态成员函数的预期调用的方法,其中虚拟函数多态性或模板可以用作“接缝”,以将模拟函数交换为真实函数。如果您可以设计或重构所有内容以使用其中一种技术,那就太好了。但是有时在凌乱的旧代码或使用外部库的代码中使事情以这种方式工作会很麻烦。

在那种情况下,另一种选择是定义一个依赖函数,该函数不是非静态成员函数(因此是自由函数或静态成员),以重定向到某个单例模拟对象。假设我们有一些转换单元(B.cpp)要进行单元测试,并且它调用该转换单元中未定义的一些非成员或静态成员函数(A::retrieveJsonData)。

通常,要对B.cpp进行单元测试,我们会注意到其所需的链接器符号,并为它们提供伪造的定义以将其存根,只是为了将目标文件B.o链接到单元测试程序中:

// Fake definition:
bool A::retrieveJsonData(std::string, Json::Value&)
{ return false; }

在这种情况下,我们不需要那个假的定义;我们稍后将定义它以重定向到模拟对象。

从专门针对有问题的函数调用的模拟类开始。如果还有其他非静态成员函数以常规方式进行测试,则此类与这些类不同。 (如果需要多个函数使用这些模拟类,则可以针对每个函数,每个类和/或针对免费函数,每个库,针对所有功能之一来完成这些模拟类;不过,您希望对其进行设置。)

class Mock_A_Static {
public:
    Mock_A_Static() {
        EXPECT_EQ(instance, nullptr);
        instance = this;
    }
    ~Mock_A_Static() {
        EXPECT_EQ(instance, this);
        instance = nullptr;
    }

    MOCK_METHOD2(retrieveJsonData, bool(std::string, Json::Value&));

private:
    static Mock_A_Static* instance;
    friend class A;
};
Mock_A_Static* Mock_A_Static::instance = nullptr;

// The function code in B.cpp will actually be directly calling:
bool A::retrieveJsonData(std::string name, Json::Value& responseJsonData)
{
    EXPECT_NE(Mock_A_Static::instance, nullptr)
        << "Mock_A_Static function called but not set up";
    if (!Mock_A_Static::instance) return false;
    return Mock_A_Static::instance->retrieveJsonData(name, responseJsonData);
}

然后将那种类型的对象放置在测试本地或夹具类中。 (尽管一次只能一个!)

TEST(BTest, Method1GetsJson)
{
    Mock_A_Static a_static;
    B b;
    EXPECT_CALL(a_static, retrieveJsonData(StrEq("data_x"), _));
    b.Method1("data_x");
}
© www.soinside.com 2019 - 2024. All rights reserved.