【问题标题】:Using googlemock with fake impls of non-virtual functions将 googlemock 与非虚拟函数的假 impl 一起使用
【发布时间】:2016-11-03 17:54:41
【问题描述】:

我有一些基于 googlemock 框架的单元测试的遗留代码。在尝试使用一些新场景扩展单元测试时,我遇到了以下问题:

class D
{
public:
  void pubMethod1();
  int pubMethod2();
  // There are pretty much non-virtual methods, both public and private
  ...
protected:
  uint method3();
  void method4();
  ...
  // Some class members are here
};

class SUT
{
public:
  ...
protected:
   D _dep;
};

应测试 SUT 类(被测软件),其实现在文件 sut.cpp 中定义。 SUT 依赖于 D 类,其实现在文件d.cpp 中。为了减少链接器依赖性,我不想将d.cpp 添加到测试中,因此当我链接测试时,D 的成员会出现许多“未定义符号”错误。为了消除错误并提供可预测的行为,我将为我的测试中的 D 方法创建假实现。但是,在 D 的方法是虚拟的之前,我仍然无法将它与 googlemock 的所有功能一起使用。

我喜欢使用 googlemock 框架中的 WillOnce、AtLeast、WillRepeatedly、Invoke 等函数的想法,因为它使单元测试的创建更容易。问题是我不喜欢改变 D 的接口,把它的方法变成虚拟的方法。是否可以使用 googlemock 函数与我将为 D 的方法创建的假实现

注意:我已经考虑过使用模板化 SUT 类的解决方案,但是我想知道是否存在其他解决方案。

【问题讨论】:

    标签: c++ unit-testing googletest googlemock


    【解决方案1】:

    首先 - 最好的办法是重新设计您的 SUT 类以通过一些抽象接口注入 D。因为我在下面描述的解决方法非常棘手 - 所以将来维护和理解并不容易......


    如果您要在 UT 目标中制作 D 类的假实现 - 那么您可以为 D 制作 Mock 类:DMock。这个DMock 不会与D 相关——不是从它派生的——但它需要与真/假D 对象配对。

    所以 - 看例子:

    创建 DMock - 模仿 D 接口(请注意,您应该只模拟公共函数 - 因为您的 SUT 只使用公共函数):

    class DMock 
    {
    public:
        MOCK_METHOD0(pubMethod1, void ());
        MOCK_METHOD0(pubMethod2, int ());
    };
    

    将您的真实(但假的)D 对象与 DMock 对象配对 - 如下所示:

    class DMockRepo
    {
    public:
        // for UT
        void addMockToUse(DMock* dMock) { freeMock.push_back(dMock); }
    
        // for implementing D fake methods
        DMock& getMock(D* original)
        {
            // TODO: use more sophisticated way to add mock to map...
            if (not usedMock[original])
            {
               usedMock[original] = freeMock.front();
               freeMock.pop_front();
            }
            return *useddMock[original];
        }
        static DMockRepo& getInstance() { return instance; } //singleton
    private:
        DMockRepo() {} // private
        static DMockRepo instance;
        std::map<D*,DMock*> usedMock;
        std::deque<DMock*> freeMock; 
    };
    

    使用mock创建D类公共方法的假实现:

    void D::pubMethod1()
    {
        DMockRepo::getInstance().getMock(this).pubMethod1();
    } 
    // 
    

    非公开方法无关紧要 - 随心所欲...

    并使用 DMockRepo 为您的 D 对象设置期望:

    TEST(Usage,Example)
    {
       DMock dMock;
       DMockRepo::getInstance().addMockToUse(&dMock);
       SUT sut; // you should know how many D objects SUT needs - I assume just one
    
       EXPECT_CALL(dMock, pubMethod1());
       sut.doSomethingThatCallsDpubMethod1();
    }
    

    【讨论】:

    • 谈到通过抽象接口注入 D。我想我有某种恐惧症,但是只有一个派生类有一个抽象接口似乎太奇怪了。另一方面,我了解这种方法在单元测试方面的优势。所以我不能决定使用这种方法))
    • 这样想:代码应该实现功能 --> 功能存在的唯一证据是它已经过测试 --> 可测试性很重要 --> 实现应该设计成一种可测试的方式。所以添加一些“只是为了测试”没有错......
    • 听起来不错))我接受了你的好建议和技巧的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    • 2020-07-02
    • 2013-08-24
    • 2021-09-04
    相关资源
    最近更新 更多