一般而言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. windows 10 开启安卓模拟器蓝屏

    上周装了个vs2017 rc 本想试试 开发安卓怎么样,花了一晚上时间终于装好了. 第二天开夜神模拟器的时候蓝屏了.. 然后就逐个卸载VS2017的功能,先是卸了 自带的仿真程序,没用.然后全部卸载掉 ...

  2. jquery实现加载更多效果

    情况是当滑动条滑动到最底部的时候,数据显示出一部分的更多 思路:获取到浏览器屏幕的高度client,文档的高度h和滑动距离顶部的距离scroll,当h<=client+scroll的时候就是滑动 ...

  3. PHP:php遍历数组each()方法总结

    each()的作用是将数组当前元素的键值对拆成一个新数组,并把下一个元素作为当前元素.比如Array(...,'Robert'=>'Bob',...)中的'Robert'=>'Bob'键值 ...

  4. IOS enum(枚举)使用

    typedef enum { MJMessageTypeMe=, MJMessageTypeOther }MJMessageType; /** *信息的类型 * */ @property (nonat ...

  5. Return-to-dl-resolve浅析

    本文介绍一种CTF中的高级rop技巧-Return-to-dl-resolve,不久前的0CTF中的babystack和blackhole就用到了这个技巧. 预备知识 在开始本文前希望大家能预先了解一 ...

  6. tomcat的启动和部署

    方法/步骤 1 一.安装JDK和Tomcat 1,安装JDK:直接运行jdk-7-windows-i586.exe可执行程序,默认安装即可. 备注:路径可以其他盘符,不建议路径包含中文名及特殊符号. ...

  7. [牛客OI测试赛2]F假的数学游戏(斯特灵公式)

    题意 输入一个整数X,求一个整数N,使得N!恰好大于$X^X$. Sol 考试的时候只会$O(n)$求$N!$的前缀和啊. 不过最后的结论挺好玩的 $n! \approx \sqrt{2 \pi n} ...

  8. Linux NFS服务器的安装与配置详解

    一.NFS服务简介 NFS是Network File System(网络文件系统).主要功能是通过网络让不同的服务器之间可以共享文件或者目录.NFS客户端一般是应用服务器(比如web,负载均衡等),可 ...

  9. 服务端Latex解析成图片或者HTML或者SVG方案

    Latex公式表达式在服务端进行转换成可用数据 使用语言与扩展 node.js Mathjax (文档链接) MathJax在nodejs上解决方案 mathjax/MathJax-node(GitH ...

  10. Oracle redo与undo 第二弹

    首先看一下undo与redo的字面意思:   undo:撤销,也就是取消之前的操作.   redo:重做,重新执行一遍之前的操作. 什么是REDO REDO记录transaction logs,分为o ...