Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 谷歌模拟非虚拟和私人功能_C++_Unit Testing_C++11_C++14_Googlemock - Fatal编程技术网

C++ 谷歌模拟非虚拟和私人功能

C++ 谷歌模拟非虚拟和私人功能,c++,unit-testing,c++11,c++14,googlemock,C++,Unit Testing,C++11,C++14,Googlemock,我试图为私有/非虚拟/静态函数编写mock,并找到了一种方法来实现同样的功能 下面是它的样子 假设我有一个类a,需要在类UsingA中模拟和使用它。这两个类的定义如下所示 class A { friend class UsingA; int privateFn() {} public: int nonVirtual() {} }; // The UsingA class class UsingA { A &a1; public: UsingA(A

我试图为私有/非虚拟/静态函数编写mock,并找到了一种方法来实现同样的功能

下面是它的样子

假设我有一个
类a
,需要在
类UsingA
中模拟和使用它。这两个类的定义如下所示

class A
{
   friend class UsingA;
    int privateFn() {}
public:
    int nonVirtual() {}
};
// The UsingA class
class UsingA {
    A  &a1;
public:
    UsingA(A & _a1) : a1(_a1) {} 
    int CallFn() {
        return a1.nonVirtual();
    }
    int CallFn2() {
        return a1.privateFn();
    }
};
我知道mock用于生成类的行为,在创建mock时,我们需要从原始类派生

但是,为了模拟行为,我决定不从原始类派生,而是注释
类A
,并生成一个同名的模拟类,即
类A
。 下面是我的模拟课的样子

// Original class A is commented / header file removed
class A  {
public:
    MOCK_METHOD0(nonVirtual, int());
    MOCK_METHOD0(privateFn, int());
};
我的测试通常是模拟测试

TEST(MyMockTest, NonVirtualTest) {
    A mstat;
    UsingA ua(mstat);

    EXPECT_CALL(mstat, nonVirtual())
    .Times(1)
    .WillOnce(Return(100));

    int retVal = ua.CallFn();

    EXPECT_EQ(retVal,100); 

}

TEST(MyMockTest, PrivateTest) {
    A mstat;
    UsingA ua(mstat);

    EXPECT_CALL(mstat, privateFn())
    .Times(1)
    .WillOnce(Return(100));

    int retVal = ua.CallFn2();

    EXPECT_EQ(retVal,100); 

}
一切正常,我可以通过这个模拟来测试
UsingA

问题是

这看起来更简单,也能达到目的,但我在浏览谷歌模拟示例时还没有见过这种示例。如果我这样做会出什么问题吗

老实说,我没找到


注意:各位,我使用
friend
仅用于演示。我的实际用例完全不同。谢谢

我们在一些测试项目中使用您的使用模拟类型来检查我们使用依赖注入传递的更大类上的回调。在我们的例子中,这些方法被声明为虚拟的


在你的情况下,他们不是。您的模拟实现将隐藏原始实现(如果有)。所以我认为这里没有问题。

错误在于您没有测试真正的代码,因为:

  • 评A班
  • 生成具有相同名称的模拟类
这些操作会改变被测代码

一个可能出错的示例:

  • 更改返回类型:
    long non-irtual
    在模拟中-以前是
    int
  • 测试一下,比如说,
    nonVirtual()==0xFF'FFFF'FFFF
    (大于
    INTMAX
    )正在执行一些操作
  • 忘记在real
    A
    中进行更改-因此real
    使用A
    具有经过测试但在real代码中永远无法访问的分支
  • 示例代码:

    class A  {
    public:
        MOCK_METHOD0(nonVirtual, long()); // change
        MOCK_METHOD0(privateFn, int());
    };
    void UsingA::processA()
    {
         if (a.nonVirtual() > VERY_BIG_NUMBER)
         {
             throw runtime_error("oops");
         }
    }
    TEST_F(UsingATest, throwOnVeryBigNumber)
    {
        EXPECT_CALL(aMock, nonVirtual()).WillOnce(Return(VERY_BIG_NUMBER + 1));
        ASSERT_THROW(objectUndertTest.processA());
    }
    
    但是real
    A
    没有改变-因此我们在UsingA类中测试不可访问的代码:

    class A  {
    public:
        int nonVirtual(); // not changed
        ...
    };
    
    最好的解决方案是(按顺序):

  • 要进行隔离测试,您必须隔离类-因此要使用依赖项注入(虚拟函数等、基接口等…)-这有时被称为
  • 测试两个类
    A
    UsingA
    w/o任何存根-在一个测试用例中一起测试它们-因此您测试真实代码-这称为
  • 按模板代码分开,对接口有很好的限制-此方法与您的方法最为相似:
  • 关于3-您可以使用以下内容:

    template <class T = A>
    class UsingA {
        T  &a1;
    public:
        UsingA(T & _a1) : a1(_a1) {} 
        long CallFn() {
            using ANonVirtualResult = std::invoke_result_t<&T::nonVirtual>;
            static_assert(std::is_same<long, ANonVirtualResult>::value);
            return a1.nonVirtual();
        }
        ...
    };
    
    模板
    类UsingA{
    T&a1;
    公众:
    UsingA(T&_a1):a1(_a1){
    long CallFn(){
    使用anInvirtualResult=std::invoke\u result\t;
    静态断言(std::is\u same::value);
    返回a1.非虚拟();
    }
    ...
    };
    
    在测试中:

    class UsingATest : public ::testing::Test
    {
    protected:
           StrictMock<AMock> aMock;
           using ClassUnderTest  = UsingA<AMock>;       
           ClassUnderTest objectUnderTest{aMock};
    };
     TEST_F(UsingATest,  useNonVirtual)
     {
            const auto VALUE = 123456;
            EXPECT_CALL(aMock, nonVirtual()).WillOnce(Return(VALUE));
            ASSERT_EQ(VALUE, objectUnderTest.CallFn());
     }  
    
    类UsingATest:public::testing::Test
    {
    受保护的:
    
    StrictMock是模拟类的变通方法,没有虚拟函数。

    Hello..谢谢你的回答。根据我的经验,我们模拟类不是为了测试被模拟的类。我们模拟类是为了测试使用被模拟类的类。我不确定在这种情况下功能如何重要,因为无论如何,模拟都不会调用original除非明确调用,否则实现。我假设一个是mock类,UsingA是一个客户机?这里不是这样吗?您好,是这样的
    UsingA
    正在使用
    moka
    我理解您想说的关于我做错了什么,但我最初的问题的目的是检查这是否真的是个坏主意,因为我可以给我的MockA编写代码,以返回任何可能产生类似于您在回答中提到的情况的内容可能不是“非常糟糕”的想法,但我在回答中提到了“缺点”。简单地说,就是这样的“手册”在被测代码和单元测试代码之间替换类型可能是难以检测到的不兼容问题的根源,因为您的测试看不到真正的代码。您可能会在gmock文档中提到的模板技巧中看到