【问题标题】:How to mock private methods in a class which is being used by public methods in Google Test?如何在 Google Test 中的公共方法使用的类中模拟私有方法?
【发布时间】:2018-10-26 07:46:50
【问题描述】:

我有一个类,比如 ClassA,它具有一些公共功能和私有功能。 公共函数依次类私有函数。 现在我的意图是通过公共功能测试私有功能。 对于公共函数,我正在尝试调用原始实现,对于私有方法,我正在尝试创建一个 Mock 函数。

我的A班是这样的,

class ClassA {
public:
    string getName(string key) {
        int value = 2;
        int code = getCode(value);
        if(code != 2)
             cout<<"Error";
        else
             return "XYZ";
    }

private:
    int getCode(int value) {
        if(value == 2)
             return 2;
        else
             return -1;
    }
};

现在我有一个像这样的 ClassA 的 Mock,

class MockA : public ClassA {
       public:
       MOCK_METHOD1(getName,string(string key)); //Mock for public method
       MOCK_METHOD1(getCode,int(int value))l //Mock for private method
}

这是我的 GoogleTest 测试用例,

TEST(ClassATest, Test1)
{
    MockA a;
    Class a1;

    EXPECT_CALL(a,getCode()).Times(1).WillOnce(Return(2));
    EXPECT_CALL(a,getName()).Times(1).WillOnce(Return(Invoke(&a1, 
ClassA::getName());
}

如您所见,对于私有方法,我使用模拟,对于公共方法,我使用 Invoke 并调用原始实现。

现在,当我编译这段代码时,我得到一个错误,

实际函数调用计数不匹配 EXPECT_CALL(a,getCode()).... 预期:被调用一次 实际:从未调用 - 不满意且活跃

现在,当我尝试使用 getCode() 的原始实现时,也喜欢,

EXPECT_CALL(a,getCode()).Times(1).WillOnce(Return(Invoke(&a1, 
ClassA::getCode());

我收到一个编译错误,说 getCode() 是不可访问的,我认为这是预期的。

到现在为止,如果您正在阅读本文,希望您能理解我的问题陈述。 我必须通过我通过 gtest 测试的公共方法传入不同的参数来测试私有方法。

我想模拟 github 中 this 文章所述的私有方法,并为我的公共方法调用原始生产代码。

我在做一些根本错误的事情吗?如果是这样,你们中的任何人都可以为我的用例提供一些更好的方法吗?

我已经尝试过 FRIEND_TEST 和 tbh,我不想对我的生产代码进行任何修改。我会尝试作为最后的手段。

【问题讨论】:

  • 你的函数不是virtual,所以你的mock方法不能用A调用。
  • 我建议你阅读Working Effectively with Legacy Code,因为它描述了如何解决这类问题。据我记得,在这本书中,其中一个建议是,如果可能的话,将私有方法提取到新类中作为公共方法。然后就可以测试了。

标签: c++ googletest gmock


【解决方案1】:

您正试图从ClassA 调用私有方法。除非有朋友声明,否则这是不可能的,但是是的,这并不理想。

问题源于您的测试设计,它应该调用公共 API 而不是实现细节。

【讨论】:

    【解决方案2】:

    迟到的答案,但我目前正在研究类似的问题并看到了这个问题。

    在您的示例中,我不太确定 Invoke() 的目的是什么,但如果您要做的只是验证对 getCode() 的调用并控制其返回值,那么您只需要模拟它一个。

    您必须修改生产代码以使私有函数成为虚拟函数,所以如果这不是一个选项,那么这当然不适合您。不过,这似乎是一个相当安全的修改。

    class ClassA {
    public:
        string getName(string key) {
            int value = 2;
            int code = getCode(value);
            if (code != 2)
                return "Error";
            return "XYZ";
        }
    
    private:
        virtual int getCode(int value) {
            if (value == 2)
                return 2;
            return -1;
        }
    };
    
    class MockA : public ClassA {
    public:
        MOCK_METHOD1(getCode, int(int value));
    };
    
    TEST(ClassATest, Test1)
    {
        MockA mockA;
        EXPECT_CALL(mockA, getCode(2)).WillOnce(Return(2));
        EXPECT_EQ(mockA.getName("key"), "XYZ");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-09
      • 2012-05-18
      • 1970-01-01
      • 2014-05-28
      • 1970-01-01
      • 1970-01-01
      • 2020-01-01
      • 1970-01-01
      相关资源
      最近更新 更多