【问题标题】:Re-routing a real function to a mocking function with Gmock?使用 Gmock 将真实函数重新路由到模拟函数?
【发布时间】:2016-04-06 11:55:04
【问题描述】:

当我从 Google 研究 Gmock 时,我已经安装并构建了项目,到目前为止运行良好。但我对模拟函数有些担心。现在我有以下文件:

myGtest.h

#ifndef MYGTEST_H_
#define MYGTEST_H_

int test(int);
int function(int);

#endif /* MYGTEST_H_ */

src_code.cpp

#include <stdio.h>
#include "myGtest.h"

int test(int a) {
    printf("NOT overridden!\n");
    return a;
}

int function(int a){

    int x = test(a);
    if(x == 0)
        return 99;
    else
        return 0;
}

myGtest_dummy.h

#ifndef MYGTEST_DUMMY_H_
#define MYGTEST_DUMMY_H_

#include "gmock/gmock.h"
#include "../myGtest/myGtest.h"

class myGtestMock
{
public:
    myGtestMock(){};
    ~myGtestMock(){};
    MOCK_METHOD1(test, int(int));
};

#endif /* MYGTEST_DUMMY_H_ */

test_program.cpp

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/myGtest/myGtest.h"
#include "src/dummy/myGtest_dummy.h"

using testing::_;
using testing::Return;
using testing::InSequence;
using ::testing::AtLeast;

extern int function(int a);
extern int test(int a);

class BTest:public testing::Test{
public:
    myGtestMock mock_test;


    int __wrap_test(int a);
};

int BTest::__wrap_test(int a){

    printf("overridden!\n");
    return a;
}

TEST_F(BTest, CallMockTest) {

    EXPECT_CALL(mock_test, test(0))
            .WillOnce(Invoke(this, &BTest::__wrap_test));

    function(99);
}

int main(int argc, char *argv[]) {

    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

你能帮我解释一下吗:如何模拟函数int test(int)?我希望一旦执行TEST_F(BTest, CallMockTest),程序就会调用function(99);。然后我的模拟函数int __wrap_test(int) 将被调用而不是int test(int)

非常感谢您的回答。

【问题讨论】:

    标签: c++ unit-testing testing googletest gmock


    【解决方案1】:

    这里的关键思想是认识到模拟是对象模拟真实对象的行为。这意味着您对它们设置期望(即:调用它们的次数、使用哪些参数等),并使用模拟来模拟一些操作(即:返回特定值或更改某些参数等)

    使用您当前的实现,当您调用 function() 时,它仍然会调用 test() 的真正实现。所以你的 EXPECT_CALL 总是会失败。理想情况下, test() 应该是您要模拟的接口的一部分。说:

    class MyInterface{
    public:
        ...
        virtual int test(int a) = 0;    
    };
    

    注意:为简单起见,我将忽略 MyInterface 的实际实现,因为无论如何我们都打算使用我们的模拟绕过实际实现。

    现在,被测函数 function() 理想情况下应该是类的一部分。稍微改变你的实现:

    class MyClass{
        ....
        int function(int a, MyInterface * interface){
            int x = interface->test(a);
            if(x == 0)
                return 99;
            else
                return 0;   
        }
    };
    

    现在,使用 function() 的第二个参数,您可以传递您创建的模拟。但在此之前,您需要定义您正在模拟 MyInterface:

    class myGtestMock : public MyInterface{
        ....
    };
    

    现在,在您的测试文件中:

    TEST_F(BTest, CallMockTest) {
        myGtestMock myMockObj;
    
        //Testing (x==0)
        EXPECT_CALL(myMockObj, test(99))   
        .Times(1)
        .WillOnce(Return(0));       //set the action
    
        EXPECT_EQ(99,function(99, &myMockObj));
        Mock::VerifyAndClear(&myMockObj); //to clear the expectation
    
        //testing else
        EXPECT_CALL(myMockObj, test(99))   
        .Times(1)
        .WillOnce(Return(1));       //set the action
    
        EXPECT_EQ(0,function(99, &myMockObj));
        Mock::VerifyAndClear(&myMockObj); //to clear the expectation
    }  
    

    你可以从 google mock CookBook学到很多技巧

    【讨论】:

    • 非常感谢您抽出宝贵时间回答我。
    • 我明白你说的。但是,我的客户只给了我源代码(src_code.c),我不能编辑它。假设我正在测试function(),并且在function() 中,调用了test()。这里的问题,test 非常非常复杂,所以我想把它做成一个存根,只想控制 返回值output args的值> 那个存根。
    • 我不能声称我了解那里提到的所有内容,但在我看来,这与您正在寻找的内容一致。
    • 谢谢。我以前研究过这个 weak 属性。但是,不幸的是,它只创建了一次从真实函数到弱函数的链接,一旦我调用真实函数,编译器总是将它重新路由到弱函数,我不能再使用真实函数了.好伤心!
    猜你喜欢
    • 1970-01-01
    • 2016-04-03
    • 1970-01-01
    • 1970-01-01
    • 2021-04-17
    • 1970-01-01
    • 2014-03-31
    • 1970-01-01
    • 2021-09-21
    相关资源
    最近更新 更多