gmock学习03---自定义输出参数
本文目的
使用gmock时,有时候需要向被mock的函数输入一些自定以参数,用来测试调用mock的方法的各种的执行情况。前几天在项目中遇到这个问题,并使用了该技巧,觉得很有用,所以总结出来,作为备忘。
一个例子
XXXClient是一个类,用于和远端服务器交互,内部实现涉及网络通讯。
class XXXClient { public: void QueryXXX(const Request&, Response&); };
内部有个函数QueryXXX,用于执行查询操作。查询的响应对象通过引用的方式传回给调用对象,避免不必要的对象拷贝。
现在有个类,会调用XXXClient::QueryXXX方法,如下面所示:
class XXXRunner { public: QueryResult DoSomething(XXXClient& oClient) { Request oReq; … // 设置oReq Response oRsp; oClient.QueryXXX(oReq, oRsp); // 这里以后的逻辑需要测试 … // 根据oRsp的内容,做一些相关逻辑,并创建QueryResult对象 return oResult; } };
现在希望做的是在测试用例中设置各种输出(oRsp),测试调用QueryXXX之后的代码逻辑,更重要的是,不希望为了执行单元测试,专门搭建一个服务器与XXXClient交互,成本太高。
Gmock的解决方法
gmock内部实现了一系列Action的宏,可以帮我们完成上面的需求。先看看代码,首先mock我们的XXXClient,
class XXXClientMock : public XXXClient { public: MOCK_METHOD2(QueryXXX, QueryResult (Request&, Response&)); };
Mock的XXXClient后,我们就可以使用mock对象在单元测试中测试了。
TEST(XXXRunnerTC, SetArgRefereeDemo) { XXXCLientMock oMock; // 设计一个期望的oRsp返回对象 Response oRsp; oRsp.attr1 = “…”; oRsp.attr2 = “any thing you like”; // 关联oRsp与mock对象的Query EXPECT_CALL(oMock, QueryXXX(_, _)). WillOnce(SetArgReferee<1>(oRsp)); // OK 设置完毕 // 调用QueryXXX XXXRunner oRunner; QueryResult oRst = oRunner.DoSomething(oMock); … // 设置断言 EXPECT_EQ(“abcdefg”, oRst.attr1); …… }
Gmock的Action
好了,现在解决了本文开始提出的问题,可以捎带做一点扩展阅读。上面用的一些API,在Gmock中称之为Action(行为),主要目的是方便快速的为mock类提供测试行为,用于测试。上面,填充oRsp对象就是用SetArgReferee<N>(value)行为实现的,通过名字,可以知道这个行为对象是用于设置参数,N是参数的索引,从0开始。类似的行为还有SetArgPointee<N>(value),设置指针参数, SetArrayArgument<N>(first, last),设置数组参数,数组范围[first,last)。
设置返回值,可以使用行为Return(Value)等一些列API,更详细的可以阅读最后的“参考资料中的gmock cheat sheet”。
有时候,可能需要设置参数和返回值,也就是同时设置多个行为,那么可以使用DoAll函数帮我们实现,DoAll相当于一个action的集合,使用示例如下:
… EXPECT_CALL(oMock, QueryXXX(_, _)). WillOnce(DoAll(SetArgReferee<1>(oRsp), Return(someObj)))); …
还可以通过Invoke行为,将负责的测试行为添加进来。
总结
用了Gtest&Gmock框架一段时间了,发现使用之他们之后,的确可以提升代码质量,并且加快bug定位,从某个侧面来说,提高的编码效率。现在,不论用什么语言写程序,在熟悉了语言本身之后,第一件事就是去熟悉这门语言相关的单元测试框架。
个人认为写单元测试不只是一种行为,更是一种信仰。
参考资料
- Gmock cheat sheet: http://code.google.com/p/googlemock/wiki/CheatSheet
- Gmock cookbook: http://code.google.com/p/googlemock/wiki/CookBook
- Stackoverflow: http://stackoverflow.com/questions/8845753/how-to-set-custom-ref-variable-in-gmock