一般而言TDD的好处是以输出为导向及早发现问题,以及方便重构(单元测试保证).
我理解,还有一个比较重要的意义是: 客观上强制了程序员写出更加友好的接口 方便测试和联调.

问题

这里我以c++举例,需求就用最简单的: 实现一个单例类(比如说一个读取数据库的单例).
好,拿到这个需求了,考虑到c++11之后static本身就是多线程安全的,所以实现一个单例模式就很简单了,如下:

// 手打不保证编译ok
class SingleDb {
public:
int getMoney(){...}
SinlgeDb(const SingleDb &) = delete;
void operator=(const SingleDb &) = delete;
static SingleDb &get() {
static SingleDb db;
return db;
}
};

ok, 单例类的主体工作基本上就完成了,代码中直接可以用SingleDb::get()就可以获得这个单例,再补充和业务相关的读取等成员函数即可.
好了,本来这样就ok了,但是老板现在要求大家每个新功能都要求写单元测试,客户端程序员(这里的客户端指代的是使用这个单例模式的程序员)调用了这个API之后就不爽了,因为他想要对他自己的业务代码进行单元测试,97影院但是在读数据库的时候无法进行打桩测试。具体遇到的问题如下:

struct Client{
 int doSth() const {
SingleDb &db = SingleDb::get();
if(db.getMoney() < 0) return -1;
}
};

完全无法测试,因为我们在写单元测试的时候无法控制db.getMoney()的输出进行控制. 因为需要做如下改造:

API适配

数据库的对象不通过静态成员函数获取,而修改成注入的方式,这样方便构造输入.
数据库单例类没有抽象基类,无法用构造类(或者说是Mock对象)替换, 需改改写成有继承体系的类.
实现:
针对以上两点,修改之后的样子

struct DbBase {
virtual int getMoney() = 0;
};
class SingleDb: public DbBase {
// 没啥变化
}; //客户端
struct Client {
DbBase &db;
explicit Client(DbBase &db): db(db) {}
int doSth() const {
if(db.getMoney() < 0) return -1;
}
};

使用(单元测试)

这样处理之后,单例类已经变成了一个更加易于单元测试的类了,以一个比较简单的单元测试框架作为例子给出(catch+fakeit)

TEST_CASE("", "")
{
using namespace fakeit;
Mock mock;
when(Method(mock, getMoney())).Return(-1);
Client c(mock.get());
REQUIRE(c.doSth() == -1);
}

这实际上是为了单元测试而把API的接口改了,不仅仅是更加易于单元测试了. 更有意义的是,把接口提升至抽象类,以后想扩展实现类,直接就新增继承类即可,单元测试都不用动(因为传入的是抽象基类).
或者哪一天用到的单元测试框架没人维护了需要切换单元测试代码,那业务代码根本也不需要动,因为抽象接口已经固定. 不用Mock框架,自己打个桩都能单元测试, 例子如下:

 
// 构造打桩继承类
struct DataBaseMock :www.97yingyuan.org public DbBase
int getMoney() {return -1;}
}; // 测试
...
DataBaseMock db;
Client c(&db);
REQUIRE(c.doSth() == -1);

总结:

实际上,撰写一个好的API的好处本身又是另外一个话题了(不仅仅有助于单元测试),但是TDD这个开发模式能够强迫程序员写出一个更加易用的API.

单元测试如何保证了易用的API的更多相关文章

  1. C# 调用网易“易盾” Web API

    易盾是网易推出的反垃圾云服务,最近准备试用一下,但发现api文档中只提供了Java, Python, PHP的示例代码,却没有C#的示例代码,于是参照Java示例代码用C#实现了一下. Java中用H ...

  2. 易飞ERP API接口调用DEMO

    一.使用场景: 1.需要开放ERP数据给第三方系统对接,如APP手机端开发,MES,OA等: 2.接口按现在主流开发,restful风格,传JSON数据,跨平台,不限开发工具: 3.不限易飞ERP,支 ...

  3. 开发笔记:用Owin Host实现脱离IIS跑Web API单元测试

    今天在开发一个ASP.NET Web API项目写单元测试时,实在无法忍受之前的笨方法,决定改过自新. 之前Web API的单元测试需要进行以下的操作: 初始配置: 1)在IIS中创建一个站点指定We ...

  4. 用Owin Host实现脱离IIS跑Web API单元测试

    开发笔记:用Owin Host实现脱离IIS跑Web API单元测试   今天在开发一个ASP.NET Web API项目写单元测试时,实在无法忍受之前的笨方法,决定改过自新. 之前Web API的单 ...

  5. Android单元测试实践

    为什么要写单元测试 首先要介绍为什么蘑菇街支付金融这边会采用单元测试的实践.说起来比较巧,刚开始的时候,只是我一个人会写单元测试.后来老板们知道了,觉得这是件 很有价值的事情,于是就叫我负责我们组的单 ...

  6. 【腾讯Bugly干货分享】安卓单元测试:What, Why and How

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d28349101cd07a5404c415 Dev Club 是一个交流移动 ...

  7. XCode中的单元测试:编写测试类和方法(内容意译自苹果官方文档)

    当你在工程中通过测试导航栏添加了一个测试target之后, xcode会在测试导航栏中显示该target所属的测试类和方法. 这一章演示了怎么创建测试类,以及如何编写测试方法. 测试targets, ...

  8. (一)NUnit单元测试心得

    由于各种缘由,一本<.Net单元测试艺术>突然出现在了我的办公桌上,于是我的单元测试之路就此开始.通过一两个月不间断的学习,以及不断结合具体的项目做开发,再结合书上的知识对单元测试有了一些 ...

  9. 玩转Node.js单元测试

    代码部署之前,进行一定的单元测试是十分必要的,这样能够有效并且持续保证代码质量.而实践表明,高质量的单元测试还可以帮助我们完善自己的代码.这篇博客将通过一些简单的测试案例,介绍几款Node.js测试模 ...

随机推荐

  1. World Wind Java开发之一(转)

    http://blog.csdn.net/giser_whu/article/details/40477235 参照<World wind Java三维地理信息系统开发指南随书光盘>以及官 ...

  2. 初学AC自动机

    前言 一直听说\(AC\)自动机是一个很难很难的算法,而且它不在\(NOIP\)提高组范围内(这才是关键),所以我一直没去学. 最近被一些字符串题坑得太惨,于是下定决心去学\(AC\)自动机. 简介 ...

  3. js处理的8种跨域方法

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  4. Cesium专栏-测量工具测距、测面、测高(附源码下载)

    Cesium Cesium 是一款面向三维地球和地图的,世界级的JavaScript开源产品.它提供了基于JavaScript语言的开发包,方便用户快速搭建一款零插件的虚拟地球Web应用,并在性能,精 ...

  5. React后台管理系统-用户列表页面

    1.页面的结构 //遍历list, 返回数据       let listBody= this.state.list.map((user,index)=> {           return ...

  6. python-的多线程处理

    书到用时方恨少,这句话在软件杯真的深深体会到了.但是对自己对于代码的领会能力还是有自信的,在做项目的时候用到了多线程的处理,开始都不知道该怎么去百度搜索关键词

  7. C# 界面跳转-登陆之后跳转至主窗口

    在登陆按钮验证成功之后可以将会话结果改为OK //验证通过之后将对话结果设置为OK(之后会载入主界面) this.DialogResult = DialogResult.OK; this.Dispos ...

  8. 基于 muse-ui 封装一个微信公众号上传插件 实现多图上传

    Vue.component('my-wx-upload', { template: ` <mu-grid-list :cols="3" :cellHeight="9 ...

  9. 1061: [Noi2008]志愿者招募

    Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 5742  Solved: 3449[Submit][Status][Discuss] Descript ...

  10. IDEA整合Mybatis+Struts2+Spring(一)--新建项目

    1.IDEA新建Maven项目: (1)依次点击File->New->Project,弹出如下对话框: (2)在弹出的New Project页面上,①选择Maven,② 勾选Create ...