一般而言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. jquery实现加载更多效果

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

  2. 【挖坑】2019年JAVA安全总结:SQL注入——新项目的开发与老项目的修复

    如何在项目中有效的防止SQL注入 写给需要的人,所有的问题源自我们的不重视. 本章略过"什么是SQL注入","如何去利用SQL注入"的讲解,仅讲如何去防御 PS ...

  3. python_11_guess任性玩

    age_of_oldboy=56 count=0 while count<3: guess_age=int(input("guess age:")) if guess_age ...

  4. Bootstrap历练实例:popover插件中的方法

    方法 下面是一些弹出框(Popover)插件中有用的方法: 方法 描述 实例 Options: .popover(options) 向元素集合附加弹出框句柄. $().popover(options) ...

  5. vmware:使用.zip文件在vmware中安装操作系统

    问题描述: 之前在vmware中安装系统时,全部都是加载的.iso文件来实现.后面同事给了一个zip包,解压后是".vmdk"等一系列具体的文件.一时间不知道怎么安装系统了,搜网页 ...

  6. SpringBoot学习4:springboot整合listener

    整合方式一:通过注解扫描完成 Listener 组件的注册 1.编写listener package com.bjsxt.listener; import javax.servlet.ServletC ...

  7. ES6学习(二):函数的扩展

    chapter07 函数的扩展 7.1 函数默认值 7.1.1 参数默认值简介 传统做法的弊端(||):如果传入的参数相等于(==)false的话,仍会被设为默认值,需要多加入一个if判断,比较麻烦. ...

  8. cf519C. A and B and Team Training(找规律)

    题意 $a$个学生,$b$个教练 可以两个学生和一个教练一组,也可以两个教练和一个学生一组,问最多组成多少组 Sol 发题解的目的是为了纪念一下自己的错误思路 刚开始想的是:贪心的选,让少的跟多的分在 ...

  9. XML字符串解析

    不多说,直接上代码: import java.io.StringReader; import org.dom4j.Document; import org.dom4j.DocumentExceptio ...

  10. 列举Asp.net页面之间传递值的几种方式和优缺点?

    一.QueryString变量 优点:使用简单,对于安全性要求不高时传递数字或是文本值非常有效. 缺点:缺乏安全性,由于它的值暴露在浏览器的URL地址中的:不能传递对象. 二. 使用Applicati ...