TDD学习笔记【四】--- 如何隔离相依性 - 基本的可测试性
前言
什么是相依性
- 根据 id,取得存在数据源中的密码(仅存放经过 hash 运算后的结果)。
- 根据传入的密码,进行 hash 运算。
- 比对数据源回传的密码,与输入密码经过哈希运算的结果,是否吻合。
简单的程序代码如下(AccountDao与Hash的内容不是重点,为节省篇幅就先省略):
using System; public class Validation
{
public bool CheckAuthentication(string id, string password)
{
// 取得数据库中,id对应的密码
AccountDao dao = new AccountDao();
var passwordByDao = dao.GetPassword(id);
// 针对传入的password,进行hash运算
Hash hash = new Hash();
var hashResult = hash.GetHashResult(password);
// 对比hash后的密码,与数据库中的密码是否吻合
return passwordByDao == hashResult;
}
} public class AccountDao
{
internal string GetPassword(string id)
{
//连接DB
throw new NotImplementedException();
}
} public class Hash
{
internal string GetHashResult(string passwordByDao)
{
//使用SHA512
throw new NotImplementedException();
}
}
相依性的问题

单元测试的角度
[TestMethod()]
public void CheckAuthenticationTest()
{
Validation target = new Validation(); // TODO: 初始化为适当值
string id = string.Empty; // TODO: 初始化为适当值
string password = string.Empty; // TODO:初始化为适当值
bool expected = false; // TODO: 初始化为适当值
bool actual;
actual = target.CheckAuthentication(id, password);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("验证这个测试方法的正确性。");
}
弹性设计的角度
如何隔离对象之间的相依性
public interface IAccountDao
{
string GetPassword(string id);
} public interface IHash
{
string GetHashResult(string password);
} public class AccountDao : IAccountDao
{
public string GetPassword(string id)
{
throw new NotImplementedException();
}
} public class Hash : IHash
{
public string GetHashResult(string password)
{
throw new NotImplementedException();
}
} public class Validation
{
private IAccountDao _accountDao;
private IHash _hash; public Validation(IAccountDao dao, IHash hash)
{
this._accountDao = dao;
this._hash = hash;
} public bool CheckAuthentication(string id, string password)
{
// 取得数据库中,id对应的密码
var passwordByDao = this._accountDao.GetPassword(id);
// 针对传入的password,进行hash运算
var hashResult = this._hash.GetHashResult(password);
// 对比hash后的密码,与数据库中的密码是否吻合
return passwordByDao == hashResult;
}
}

原文可參考 Martin Fowler 的文章:Inversion of Control Containers and the Dependency Injection pattern
As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.
如何进行测试
[TestMethod()]
public void CheckAuthenticationTest()
{
IAccountDao accountDao = null;// TODO: 初始化为合适的值
Hash hash = null;// TODO: 初始化为合适的值
Validation target = new Validation(accountDao, hash);
string id = string.Empty; // TODO: 初始化为合适的值
string password = string.Empty;//TODO: 初始化为合适的值
bool expected = false;// TODO: 初始化为合适的值
bool actual;
actual = target.CheckAuthentication(id, password);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("验证这个测试的正确性。");
}
public class StubAccountDao : IAccountDao
{
public string GetPassword(string id)
{
return "Hello World";
}
}
接着用同样的方式,让 StubHash 的 GetHashResult,也回传 "Hello World",代表 hash 后的结果。程序代码如下:
public class StubHash : IHash
{
public string GetHashResult(string password)
{
return "Hello World";
}
}
聪明的读者朋友们,应该知道接下来就是来写单元测试的 3A pattern,单元测试程序代码如下:
[TestMethod()]
public void CheckAuthenticationTest()
{
//arrange
// 初始化StubAccountDao,来当作IAccountDao的执行对象
IAccountDao dao = new StubAccountDao();
// 初始化StubHash,来当作IStubHash的执行对象
IHash hash = new StubHash();
Validation target = new Validation(dao, hash);
string id = "随便写";
string password = "随便写";
bool expected = true;
bool actual;
//act
actual = target.CheckAuthentication(id, password);
//assert
Assert.AreEqual(expected, actual);
}

延伸思考
结论
补充
备注:这个系列是我毕业后时隔一年重新开始进入开发行业后对大拿们的博文摘要整理进行学习对自我的各个欠缺的方面进行充电记录博客的过程,非原创,特此感谢91 等前辈
TDD学习笔记【四】--- 如何隔离相依性 - 基本的可测试性的更多相关文章
- MySql学习笔记四
MySql学习笔记四 5.3.数据类型 数值型 整型 小数 定点数 浮点数 字符型 较短的文本:char, varchar 较长的文本:text, blob(较长的二进制数据) 日期型 原则:所选择类 ...
- 官网实例详解-目录和实例简介-keras学习笔记四
官网实例详解-目录和实例简介-keras学习笔记四 2018-06-11 10:36:18 wyx100 阅读数 4193更多 分类专栏: 人工智能 python 深度学习 keras 版权声明: ...
- C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...
- IOS学习笔记(四)之UITextField和UITextView控件学习
IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- Typescript 学习笔记四:回忆ES5 中的类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- ES6学习笔记<四> default、rest、Multi-line Strings
default 参数默认值 在实际开发 有时需要给一些参数默认值. 在ES6之前一般都这么处理参数默认值 function add(val_1,val_2){ val_1 = val_1 || 10; ...
- muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制
目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...
随机推荐
- CSS3的filter用法
最近到处看到有人在说CSS3的filter一直没有时间自己去测试这效果.今天终于抽出时间学习这个CSS3的Filter.不整不知道呀,一整才让我感到吃惊,太强大了.大家先来看个效果吧: 我想光看上面的 ...
- 调用WebServices超时
1. 服务器端设置超时 在 web.config 的 system.web 里添加如下配置项: < httpRuntimeexecutionTimeout="300000"/ ...
- 【转】iOS9适配
Demo1_iOS9网络适配_改用更安全的HTTPS iOS9把所有的http请求都改为https了:iOS9系统发送的网络请求将统一使用TLS 1.2 SSL.采用TLS 1.2 协议,目的是 强制 ...
- solr基本入门
一直想接触下搜索,虽然之前也玩了下solr,但一直没深入,所以也都忘得差不多了,现在solr都6.1了,发展真快.重新拾起,记录下也好,为以后出问题查找起来快一点. 1.搜索最重要的概念就是倒排索引, ...
- centos7 开放端口
开启端口 firewall-cmd --zone=public --add-port=80/tcp --permanent 命令含义: --zone #作用域 --add-port=80/tc ...
- C和指针 第十五章 输入输出缓冲
对于C,所有的I/O操作都只是简单的从程序移进或移出字节,这种字节流便成为流(stream),我们需要关心的只是创建正确的输出字节数据,以及正确的输入读取数据,特定的I/O设备细节都是对程序隐藏的. ...
- Linux下安装tensorflow
- linux命令crontab
1.需求 服务端计划任务执行 2.例子 使用crontab命令 参考:http://justjavac.com/other/2013/09/22/linux-scheduled-task-cronta ...
- 耿丹CS16-2班课堂测试作业汇总
Deadline: 2016-11-01 11:59 作业内容 课堂测试作业总结 00.题目得5分,多半扣在格式上,有些同学代码写得很过分,已经很仁慈对待,同学们珍惜之: 01.界面设计得分不好,换行 ...
- Activity系列讲解---三大基本状态与七大生命周期函数
简介:四大组件之一,在应用中一个Activity可以用来表示一个界面,可以理解为用户可视化界面,一个android应用必须通过Activity来运行和启动. 1.三大基本状态与七大生命周期函数 2.代 ...