C++类的完美单元测试方案——基于C++11扩展的friend语法
版权相关声明:本文所述方案来自于《深入理解C++11—C++11新特性解析与应用》(Michael Wong著,机械工业出版社,2016.4重印)一书的学习。
项目管理中,C语言工程做单元测试用例直接写就可以了,对于C++语言工程,曾经听到过“C++类的私有成员在外部无法访问没法写啊,就测测接口吧?”,对于项目管理人员与开发人员,作为C/C++语言使用者的你是否也有过这种烦恼?
提案“单元测试用例以私有成员函数的形式写在被测类的里面,通过预处理宏开关,使得发布时不让单元测试编译链接进去”,方案在语法上可以,而且也没有破坏封装性,但是测试用例的量很庞大跟生产代码搞在一起好不爽有么有,不优雅,没有人会这么做会让自己的代码变成那样。
提案“通过预处理宏开关,使得单元测试时将private替换为public”,看上去这个提案简单,但是也不完美,使用默认的private成员限制(如class FooTest : Foo { int x;}),这个方案处理不了这个情形,另外这个方案要求你的程序中变量名和函数名中不能含有private子字符串。
下面将介绍书中的类单元测试的完美解决方案:
1.语法知识准备:“可以为类模板声明友元”(C++11新特性)
template<typename T>
class Foo {
friend T;
}
如果FooTest是类,那么Foo<FooTest>会被实例化为一个定义了类FooTest为其友元的Foo<FooTest>类。
而若T为内置类型时,如Foo<int>会被实例化为一个普通的没有友元定义的类型。
2.生产代码中的类模板实例化
template<typename T>
class FooT {
public:
friend T;
void DoSomthing(){}
private:
int m_data;
}
using Foo = FooT<int>;
后续的生产代码可以直接使用Foo,生产代码很优雅。
3.测试代码中的设计(与原书稍有出入,根据自身需求调整)
class FooTester; //测试类
using FooTestee = FooT<FooTester>; //被测试类
class FooTester{
public:
void Testcase1() {}
}
在FooTester类里面,我们可以测试FooTestee的私有或公有成员函数,可以访问FooTestee的私有成员变量进行验证。总之单元测试很优雅。
学习了上面的完美方案,为C++11的新特性感到欢欣鼓舞,做一名重视单元测试的对自己有要求的C/C++工作者。感谢深入理解C++11这本书。
C++类的完美单元测试方案——基于C++11扩展的friend语法的更多相关文章
- 真正意义上的spring环境中的单元测试方案spring-test与mokito完美结合
真正意义上的spring环境中的单元测试方案spring-test与mokito完美结合 博客分类: java 测试 单元测试SpringCC++C# 一.要解决的问题: spring环境中 ...
- 如何写好、管好单元测试?基于Roslyn+CI分析单元测试,严控产品提测质量
上一篇文章中,我们谈到了通过Roslyn进行代码分析,通过自定义代码扫描规则,将有问题的代码.不符合编码规则的代码扫描出来,禁止签入,提升团队的代码质量. .NET Core技术研究-通过Roslyn ...
- JMessage是让App 同时集成 Push 功能与 IM 功能最完美的方案
历经几个月的沉寂,以及兄弟们的奋战,极光推送的兄弟产品诞生了:极光IM,英文名 JMessage. 极光IM 是我们团队基于大量客户的需求反馈,在很多客户的殷切期盼下所开发的.团队成员一方面要支撑极光 ...
- 基于类(Java)和基于原理(JavaScript)的对象系统的比较
Java:面向对象编程语言,吸收了C++语言的各种优点,丢掉了C++让人头疼的多继承.指针等概念.具有功能强大和简单易用的两大特征.Java具有简单性.面向对象.分布式.健壮性.安全性.平台独立与可移 ...
- svg操纵方案 基于 D3 还是 angular?
之前还是想简单了, 现在重新写这篇.把逻辑拆分粒度的辨析,放到外面去. 问题提出:svg控制方案 基于 D3 还是 angular 根据这个,html 4种展现样式:普通的html,svg,2D ca ...
- 基于Spark自动扩展scikit-learn (spark-sklearn)(转载)
转载自:https://blog.csdn.net/sunbow0/article/details/50848719 1.基于Spark自动扩展scikit-learn(spark-sklearn)1 ...
- 基于C++11的线程池实现
1.线程池 1.1 线程池是什么? 一种线程管理方式. 1.2 为什么用线程池? 线程的创建和销毁都需要消耗系统开销,当线程数量过多,系统开销过大,就会影响缓存局部性和整体性能.而线程池能够在充分利用 ...
- 基于C++11的数据库连接池实现
0.注意 该篇文章为了让大家尽快看到效果,代码放置比较靠前,看代码前务必看下第4部分的基础知识. 1.数据库连接池 1.1 是什么? 数据库连接池负责分配.管理和释放数据库连接,属于池化机制的一种,类 ...
- ExtJS4.2学习(13)基于表格的扩展插件---rowEditing
鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-11-24/182.html --------------- ...
随机推荐
- MCB2300的CTM1050(CAN) - 系列示意图
这一系列示意图由Portel DXP 2004绘. 截图: 文件下载: CTM1050.7z 版权声明:本文博客原创文章,博客,未经同意,不得转载.
- 在微信浏览器里使用js或jquery实现页面重新刷新
function refresh() { var random = Math.floor((Math.random() * 10000) + 1); var url = decodeURI(windo ...
- 有了VARCHAR,为什么还要有CHAR?
VarcharVarchar往往用来保存可变长度的字符串.简单的说,我们只是给其固定了一个最大值,然后系统会根据实际存储的数据量来分配合适的存储空间.为此相比CHAR字符数据而言,其能够比固定长度类型 ...
- JS 中按键处理
<script type="text/javascript"> //关于键的问题 onload = function () { ...
- 【shell】递归函数----调用自身的函数
什么是递归函数? 一句话,调用自己的函数称为递归函数! #!/bin/bash declare -i count checkoutCount(){ read -p "Enter an cou ...
- System.Data.SQLite 中GUID的处理
原文:System.Data.SQLite 中GUID的处理 项目中正好用到System.Data.SQLite,在手持上使用这个数据库,因为要做数据同步,所以表中的主键都是Guid的数据类型. 在数 ...
- Android零基础入门第20节:CheckBox和RadioButton使用大全
原文:Android零基础入门第20节:CheckBox和RadioButton使用大全 本期先来学习Button的两个子控件,无论是单选还是复选,在实际开发中都是使用的较多的控件,相信通过本期的学习 ...
- C#高性能大容量SOCKET并发(十一):编写上传客户端
原文:C#高性能大容量SOCKET并发(十一):编写上传客户端 客户端封装整体框架 客户端编程基于阻塞同步模式,只有数据正常发送或接收才返回,如果发生错误则抛出异常,基于TcpClient进行封装,主 ...
- .net core 利用Selenium和PhantomJS后台生成EChart图片
1.引用 NuGet安装: Selenium.Support Selenium.WebDriver Selenium.WebDriver.PhantomJS.CrossPlatform (分布Lin ...
- CentOS7 无法使用yum命令,无法更新解决方法
前言 设置网卡开机自动启动 设置国内dns服务器系统 修改CentOS-Base.repo中的地址 所参考的文章地址 前言 刚安装完的CentOS7的系统,发现无法使用yum命令进行更新,在更新的时候 ...