本文基于gmock版本:1.5.0,本文内容不保证对后续版本一定正确。
下载gmock:http://code.google.com/p/googlemock/downloads/list
安装:将下载的压缩包解压出来,到解压目录下执行:
./configure
然后执行:
make
注意,这个make不会编译Google Mock自己的测试用例。要编译它们,需要到解压目录下的“make”子目录下,执行:
make gmock_test
文章来源:http://www.codelast.com/
然后就会看到该目录下生成了一个可执行文件 gmock_test ,执行这个可执行文件,就可以看到Google Mock测试用例的执行结果(应该是成功的,如果有失败,则应修改Makefile使之成功):
Running main() from gmock_main.cc
[==========] Running 13 tests from 3 test cases.
[----------] Global test environment set-up.
[----------] 6 tests from InitGoogleMockTest
[ RUN ] InitGoogleMockTest.ParsesInvalidCommandLine
[ OK ] InitGoogleMockTest.ParsesInvalidCommandLine (0 ms)
[ RUN ] InitGoogleMockTest.ParsesEmptyCommandLine
[ OK ] InitGoogleMockTest.ParsesEmptyCommandLine (0 ms)
[ RUN ] InitGoogleMockTest.ParsesSingleFlag
[ OK ] InitGoogleMockTest.ParsesSingleFlag (0 ms)
[ RUN ] InitGoogleMockTest.ParsesUnrecognizedFlag
[ OK ] InitGoogleMockTest.ParsesUnrecognizedFlag (0 ms)
[ RUN ] InitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag
[ OK ] InitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag (0 ms)
[ RUN ] InitGoogleMockTest.CallsInitGoogleTest
[ OK ] InitGoogleMockTest.CallsInitGoogleTest (0 ms)
[----------] 6 tests from InitGoogleMockTest (1 ms total)
[----------] 6 tests from WideInitGoogleMockTest
[ RUN ] WideInitGoogleMockTest.ParsesInvalidCommandLine
[ OK ] WideInitGoogleMockTest.ParsesInvalidCommandLine (0 ms)
[ RUN ] WideInitGoogleMockTest.ParsesEmptyCommandLine
[ OK ] WideInitGoogleMockTest.ParsesEmptyCommandLine (0 ms)
[ RUN ] WideInitGoogleMockTest.ParsesSingleFlag
[ OK ] WideInitGoogleMockTest.ParsesSingleFlag (0 ms)
[ RUN ] WideInitGoogleMockTest.ParsesUnrecognizedFlag
[ OK ] WideInitGoogleMockTest.ParsesUnrecognizedFlag (0 ms)
[ RUN ] WideInitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag
[ OK ] WideInitGoogleMockTest.ParsesGoogleMockFlagAndUnrecognizedFlag (0 ms)
[ RUN ] WideInitGoogleMockTest.CallsInitGoogleTest
[ OK ] WideInitGoogleMockTest.CallsInitGoogleTest (0 ms)
[----------] 6 tests from WideInitGoogleMockTest (0 ms total)
[----------] 1 test from FlagTest
[ RUN ] FlagTest.IsAccessibleInCode
[ OK ] FlagTest.IsAccessibleInCode (0 ms)
[----------] 1 test from FlagTest (0 ms total)
[----------] Global test environment tear-down
[==========] 13 tests from 3 test cases ran. (1 ms total)
[ PASSED ] 13 tests.
文章来源:http://www.codelast.com/
其他记录:
(1)Google Mock对象在析构的时候会检查mock函数的执行结果是否与预期相符,如果mock对象一直存在,最终的检查就不会发生。因此,如果你在堆(heap)中创建mock对象的话,最好使用内存泄漏检查工具来确定你的test是否做好了mock对象销毁工作。
(2)Google Mock要求在调用mock函数之前设置好预期的结果,否则其行为就是“未定义”的。
(3)使用EXPECT_CALL() 宏来设置一个mock函数调用的预期结果。其语法为:
EXPECT_CALL(mock_object, method(matchers))
.Times(cardinality)
.WillOnce(action)
.WillRepeatedly(action);
第一个参数是mock对象,第二个参数是mock函数名及其参数。二者中间是以逗号(而不是点号)分隔的,至于为什么是这样,回答只有一个:技术原因。
宏后面还可以紧跟若干语句,以提供对mock函数调用的预期结果的更多信息。这种风格的语法被一些人称作是“特定领域语言”(Domain-Specific Language,DSL)。
(4)Google Mock中有一些可能初次见到时感觉比较陌生的概念,例如 matcher,cardinality,etc. 这些概念在gmock的手册中都有详细说明,网上也可以找到一些中文文档,为了能真正用起来gmock,一定要看清了这些概念的含义。
(5)一个返回值为 bool 类型的mock函数默认是返回 false 的!所以,如果你没有设置函数的默认返回值,你的test函数被调用了之后很可能只执行了一部分(例如,你的test函数调用了一个mock函数,而该函数在返回 false 时,将不再继续执行其后的代码),这样你的test将不能覆盖某函数的全部代码,而这并不是你乐见的,切记。
(6)在mock对象析构时,对“期望”的检验才会被执行,所以,如果你的mock对象一直没有析构(例如,你在堆中创建了一个mock对象,却忘了删除它 。有人说可以用内存检查工具来防止这一点,但是要知道没有工具是可以保证100%可靠的),则检验一直不会被执行。如果你担心这种情况,就可以主动进行检验:
Mock::VerifyAndClearExpectations(&mock_object):
该方法返回一个bool值,以显示检验是否成功(true代表成功)。所以,你可以把它嵌套在EXPECT_TRUE()或者ASSERT_TRUE()里面来测试检验结果。
文章来源:http://www.codelast.com/
(7)gmock安装包解压目录下的“scripts”子目录下,有一个Python脚本fuse_gmock_files.py,这个脚本一般用不到,它是用来合并Google Mock的文件的。Google Mock包含N多文件,如果你要自己扩充它的功能,那么你就需要自行修改某些文件的源码,如果你把Google Mock拷贝到另一台计算机上,从头开始修改很多个文件的源码可能就很麻烦,所以脚本fuse_gmock_files.py就可以将Google Mock原来的N多文件合并为三个文件:gtest/gtest.h,gmock/gmock.h 和 gmock-gtest-all.cc。这样的话就方便多了。
(8)Google Mock有三个(主要的)指导文档,其难度由低到高分别为:ForDummies,CheatSheet,CookBook。所以,如果你刚接触gmock,应该按这个顺序依次学习那三个文档。
(9)对普通函数,使用宏 MOCK_METHODn 来定义一个模拟函数,其中n是你要模拟的函数的参数的个数,例如,你要模拟的函数没有参数,则应使用 MOCK_METHOD0。对const函数,你就要改用宏 MOCK_CONST_METHODn 来定义。
(10)static/静态 函数如何mock?
在Google Mock的官方“常见问题”的回答中(请点击这个链接,在文章中搜索“static”即可定位到),Google是这样说的:You can, but you need to make some changes(可以,但是你需要做一些修改).Google说,如果你需要mock一个静态函数,那说明你的程序模块过于“紧耦合”了(并且灵活性不够、重用性不够、可测试性不够),你最好是定义一个小接口,通过这个接口来调用那个函数,然后就容易mock了。
这就是Google Mock给出的答案,至于你怎么想的,又会不会按它的建议去做,决定权就在你自己了。
(11)使用 ON_CALL() 宏可以设定mocker函数的返回值,例如以下代码:
ON_CALL(myMockObj, myFunc())
.WillByDefault(Return(123));
表示“命令”函数 myFunc() 的返回值为 123,其中 myMockObj 是mocker对象,函数 myFunc() 是在该mocker类中定义的模拟函数。可见,有了Goolge Mock这样的工具,我们就可以随意“控制”一个函数的行为,让它返回我们想要返回的值,从而可以使得单元测试可以按我们的意愿来进行——有时候,你必须要这么做,例如,你的一个函数 myInvoker() 调用了 myFunc() 函数,而myFunc() 函数的返回值是根据当前时间而变化的,因此其返回值不定,我们无法使其返回一个固定的值,从而我们在对 myInvoker() 做单元测试的时候,就“很难测”了,这个时候,我们就要命令 myFunc() 永远返回我们想要的值,从而可以使得对 myInvoker() 的单元测试可以顺利进行。
多么妙的想法!这就是mock的巨大作用,尽管它只是一个后台的“模仿者”(mocker),但是它产生的作用,却是真真切切的。
文章来源:http://www.codelast.com/
(12)编译你自己的单元测试的时候遇到“undefined reference to `vtable for XXX”,“undefined reference to `typeinfo for XXX'”错误?
出现这个错误,我可以提醒你的一点是:检查你的mocker类中,是否按照gmock文档的要求,把某些函数定义成纯虚函数了。比如我有一个tobe mocked的类:
class CTobeMocked
{
public:
CTobeMocked() {}
virtual ~CTobeMocked() {}
public:
virtual double myFunc(const string &str) = 0;
};
这个类就是要被mock的类,注意里面的函数myFunc()是被定义成纯虚函数的,如果你漏了后面的“ = 0”,那么你编写了相应的mocker类之后,编译的时候就会出错。
我的mocker类如下:
class CMyMocker : public CTobeMocked
{
public:
CMyMocker() {}
virtual ~CMyMocker() {}
public:
MOCK_METHOD(myFunc, double(const string &str));
};
这样就可以了。
文章来源:https://www.codelast.com/
➤➤ 版权声明 ➤➤
转载需注明出处:codelast.com
感谢关注我的微信公众号(微信扫一扫):