mock non-virtual methods
生产代码中有很多类方法是非虚的,而为了在Gtest中解除这些非必需的依赖,可以通过Gmock的mock non-virtual methods using templates方法来达到目的。
在此之前,需要了解一种设计模式:Dependency Injection,依赖注入。虽然这个概念始于Java和.net,但在面向对象编程中,C++代码同样应该遵循。
Ps:软件工程中的一个重要的理念就是关注分离(Separation of concern, SoC)。依赖注入不是目的,它是一系列工具和手段,最终的目的是帮助我们开发出松散耦合(loose coupled)、可维护、可测试的代码和程序。这条原则的做法是大家熟知的面向接口,或者说是面向抽象编程。
如何重构代码达到DI的目的呢,下面是一个例子。
原代码:
class A{
public:
int Funtion1(B& obj) {
//do something
std::string str = “mock non-virtual methods using templates”;
auto rst = obj.Function2(str);
//do something
}
}
class B{
public:
int Funtion2(std::string _str){ puts(_str.c_str()); }
}
当我们对类A的方法Function1进行UT防护的时候,不关心其中类B的方法Function2的执行结果,这时候该如何对其进行mock呢(Function2是非虚的)?
在以上这种代码结构中,答案是无法进行mock!除非把Function2修改为virtual或者使用下面的方法:
修改后:
emplate <class T1 >
class RefactorA{
public:
int Funtion1(T1 & obj) {
//do something
std::string str = “mock non-virtual methods using templates”;
auto rst = obj.Function2(str);
//do something
}
}
重构之后,类RefactorA变成了类模板,在实例化的时候把依赖的类B显式的“注入”进去,这时候进行UT的时候,就可以把“注入”的类B的方法Function2 进行mock,代码如下:
//对类B中的Function2进行mock
class mockB
{
public:
MOCK_METHOD1(Funtion2, int (std::string ));
};
/对类A进行UT测试
class RefactorA _UT : public :: testing::Test
{
protected:
virtual void SetUp(){}
virtual void TearDown(){} RefactorA < mockB > mockObjA;//实例化模板类
}; TEST_F(RefactorA _UT , Funtion1)
{
//期望类B的方法Function2被调用至少一次,返回值为100,参数为任意字符串
mockB mockObjB;
EXPECT_CALL(mockObjB, Funtion2 (_))
.Times(AtLeast())
.WillOnce(Return()); auto rst = mockObjA.Function1( mockObjB );//注意这里传入的是mock出来的对象 EXPECT_TRUE( rst );
}
把类B的方法Function2 mock之后,UT的重点就可以放在对Function1的其它分支上了。
重点:将类A改写为类模板之后,在生产代码中,需要使用真正的类B对象来进行模板类的实例化,而在测试代码中,则需要使用mock出来的类B对象进行模板类的实例化。它们之间的无关的,这与mock接口类的虚函数有着本质的区别。
附:
类模板方法的声明和定义有以下4种方法,可以酌情使用:
① 荐做法是方法在定义的时候就进行实现(类RefactorA);
② 再者是,声明在模板类中,实现在模板类外,但要在一个文件中;
③ 把方法的实现写入xxx.inl文件,然后在模板类的结尾使用#include “xxx.inl”;
④ 把方法的实现写入xxx.cpp文件,但在cpp文件的最开始需要将模板类实例化。
总之,为了写出可UT的代码,需要时刻牢记“依赖注入”这个原则。
欢迎讨论。
mock non-virtual methods的更多相关文章
- What’s wrong with virtual methods called through an interface
May 31, 2016 Calling a virtual method through an interface always was a lot slower than calling a st ...
- why do we need virtual methods in C++?
http://stackoverflow.com/questions/2391679/why-do-we-need-virtual-methods-in-c Basic idea: when mark ...
- 【转载】#349 - The Difference Between Virtual and Non-Virtual Methods
In C#, virtual methods support polymorphism, by using a combination of the virtual and override keyw ...
- Rhino Mock
mock interfaces, delegates and classes, including those with parameterized constructors. set expecta ...
- [转载] google mock cookbook
原文: https://code.google.com/p/googlemock/wiki/CookBook Creating Mock Classes Mocking Private or Prot ...
- CLR via C# 3rd - 08 - Methods
Kinds of methods Constructors Type constructors Overload operators Type con ...
- 8.Methods(一)
1.Instance Constructors and Classes (Reference Types) Constructors methods : 1.allow an instance of ...
- (转) Virtual function
原文地址:http://en.wikipedia.org/wiki/Virtual_function In object-oriented programming, a virtual functio ...
- Should I expose asynchronous wrappers for synchronous methods?
Lately I've received several questions along the lines of the following, which I typically summarize ...
- why pure virtual function has definition 为什么可以在基类中实现纯虚函数
看了会音频,无意搜到一个frameworks/base/include/utils/Flattenable.h : virtual ~Flattenable() = 0; 所以查了下“纯虚函数定义实现 ...
随机推荐
- UWP添加数字证书导出安装包本地安装
先生成一个简单的HelloWorld应用程序 <Page x:Class="HelloWorld.MainPage" xmlns="http://schemas.m ...
- navicat Premium远程链接mysql报错
1,报错1057,原来是没有远程权限连接mysql 2.打开my.ini文件,添加skip-grant-tables跳过验证 3.添加到path环境变量,前面是英文下的分号 4.切换到cmd,输入my ...
- 了解 object.defineProperty 的基本使用方法(数据双向绑定的底层原理)
Object.defineProperty 给一个对象定义一个新的属性或者在修改一个对象现有的属性,并返回这个对象 语法: Object.defineProperty(参数1,参数2,参数3) 参数1 ...
- Python设计模式--单例模式(懒汉式)
1. 单例模式 --> 单一(唯一)的实例. 在整个运行时间内, 内存中只有一个对象, 一般该对象涉及网络,资源等操作. 2. 单例模式一般分为懒汉式和饿汉式 懒汉式内存占用更加合理. 3. 调 ...
- chckBox样式的修改
在Android开发中,系统自带的默认CheckBox由于比较简陋,可能难以满足部分人的审美需求,不过,Android具有很强的扩展性,自定义CheckBox其实也很简单. 1. Layout中定义C ...
- 【hihocoder 1032】最长回文子串
[题目链接]:http://hihocoder.com/problemset/problem/1032 [题意] [题解] 原文地址:https://segmentfault.com/a/119000 ...
- 【codeforces 732F】Tourist Reform
[题目链接]:http://codeforces.com/contest/732/problem/F [题意] 给你一张无向图; n个点,m条边; 让你把这张图改成有向边 然后定义r[i]为每个点能够 ...
- Java基础学习总结(60)——Java常用的八种排序算法
1.直接插入排序 经常碰到这样一类排序问题:把新的数据插入到已经排好的数据列中. 将第一个数和第二个数排序,然后构成一个有序序列 将第三个数插入进去,构成一个新的有序序列. 对第四个数.第五个数--直 ...
- 使用Eclipse进行远程调控
什么是远程调试,就是在A机器上利用Eclipse单步跟踪调试B机器上的Web应用,当然调试A机器上Web应用也是没有问题的,90%我都是调试本机的Web应用,远程调试的意义我想我不用说了,大家都会想到 ...
- 洛谷 U6254 最低费用
U6254 最低费用 题目背景 小明暑假去国外游玩,到了最后一天,却发现自己的钱还不一定够去机场,于是他开始对国外特殊的交通方式进行研究,但是他发现路段的错综复杂使他头脑昏花,于是他打开电脑,希望你去 ...