使用 Gmock 将真实函数重新路由到模拟函数?
Re-routing a real function to a mocking function with Gmock?
当我从 Google 研究 Gmock 时,我已经安装并构建了项目,目前运行良好。但是我对模拟函数有些担心。现在我有以下文件:
<1> myGtest.h
#ifndef MYGTEST_H_
#define MYGTEST_H_
int test(int);
int function(int);
#endif /* MYGTEST_H_ */
<2> 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;
}
<3> 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_ */
<4> 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)
.
非常感谢您的回答。
这里的关键思想是认识到 Mock 是模拟真实对象行为的对象。这意味着您对它们设置了期望(即:它们被调用的次数、使用哪些参数等),并使用模拟来模拟一些操作(即:返回特定值或更改某些参数等)
对于您当前的实现,当您调用 function() 时,它仍然会调用 test() 的真正实现。所以你的 EXPECT_CALL 总是会失败。理想情况下,test() 应该是您要模拟的接口的一部分。说:
class MyInterface{
public:
...
virtual int test(int a) = 0;
};
注意:为简单起见,我将忽略 MyInterface 的实际实现,因为无论如何我们打算使用我们的模拟绕过实际实现。
现在,被测函数 function() 理想情况下应该是 class 的一部分。稍微改变一下你的实现:
class MyClass{
....
int function(int a, MyInterface * interface){
int x = interface->test(a);
if(x == 0)
return 99;
else
return 0;
}
};
现在,使用 function() 的第二个参数,您可以传递您创建的 mock。但在此之前你需要定义你正在模拟 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
中学到很多技巧
当我从 Google 研究 Gmock 时,我已经安装并构建了项目,目前运行良好。但是我对模拟函数有些担心。现在我有以下文件:
<1> myGtest.h
#ifndef MYGTEST_H_
#define MYGTEST_H_
int test(int);
int function(int);
#endif /* MYGTEST_H_ */
<2> 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;
}
<3> 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_ */
<4> 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)
.
非常感谢您的回答。
这里的关键思想是认识到 Mock 是模拟真实对象行为的对象。这意味着您对它们设置了期望(即:它们被调用的次数、使用哪些参数等),并使用模拟来模拟一些操作(即:返回特定值或更改某些参数等)
对于您当前的实现,当您调用 function() 时,它仍然会调用 test() 的真正实现。所以你的 EXPECT_CALL 总是会失败。理想情况下,test() 应该是您要模拟的接口的一部分。说:
class MyInterface{
public:
...
virtual int test(int a) = 0;
};
注意:为简单起见,我将忽略 MyInterface 的实际实现,因为无论如何我们打算使用我们的模拟绕过实际实现。
现在,被测函数 function() 理想情况下应该是 class 的一部分。稍微改变一下你的实现:
class MyClass{
....
int function(int a, MyInterface * interface){
int x = interface->test(a);
if(x == 0)
return 99;
else
return 0;
}
};
现在,使用 function() 的第二个参数,您可以传递您创建的 mock。但在此之前你需要定义你正在模拟 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
中学到很多技巧