为何要有这篇文章呢?数据库
我的在不断实践中愈加以为,单元测试对于代码质量的保障真的太有意义了,至少能体如今以下两个方面:设计模式
①让你写出更好的代码,可测试的代码必定是优雅的代码(为了可测试,你必需要解耦,必需要遵循较好的设计模式)网络
②让你重构之类的操做更加放心,由于测试会告诉你影响了哪些功能点单元测试
因此想简单写写关于单元测试的一些基础相关东西测试
单元测试是什么?spa
也不想上网找定义,就说说大概本身的几点理解:设计
单元测试是单元的,即只是对一个系统里某个特定模块(或者方法)有限条件下(好比某个if分支)的测试code
单元测试不该该依赖任何外部系统(如网络/数据库甚至是时间)全部依赖都应该经过依赖注入的形式获取blog
单元测试是能够重放的,一次成功后任意状况重试应该也老是成功的string
举个栗子
为了说明白单元测试,下面写一个简单的代码
首先他的功能很简单,返回当天是什么时刻(上午/下午之类的),具体需求就是
0到6点返回“晚上” 6到12点返回“上午” 12到18点返回”下午” 18点到24点显示”傍晚”(别纠结谁家傍晚还能到24点这种细节了)
此时咱们可能会写出以下代码:
1 public string 当天时刻() 2 { 3 DateTime time = DateTime.Now; 4 if(time.Hour >= 0 && time.Hour < 6) 5 { 6 return "晚上"; 7 } 8 if(time.Hour >= 6 && time.Hour < 12) 9 { 10 return "上午"; 11 } 12 if(time.Hour >= 12 && time.Hour < 18) 13 { 14 return "下午" 15 } 16 return "傍晚"; 17 }
上面这段代码,从功能角度来讲,是完美的,他完美的实现了需求。
可是从测试的角度来讲,他是灾难性的,由于这个代码不可测试。
为何这么说呢?
如今电脑时间是上午9点,我运行这个程序,我预期他返回是“上午”。
好了,测试经过,而后另外一个小伙伴可能他电脑时钟设置有问题也同一时刻运行却返回了“傍晚”
或者说我在下午的时候运行他返回了给我“下午”
在这里,这个程序执行的结果不肯定,他会受到电脑时钟的影响。
为何这个代码不能够测试呢?
咱们来分析下这个代码,最重要的一点就是
DateTime time = DateTime.Now;
这句话是获取电脑当前的时间。
咱们须要的功能是,告诉我如今是什么时刻,而后这段代码里杂合了获取时间的这么一个非需求内的功能(违反了单一职责)
另外”获取时间”由于是受到外部条件控制(电脑时钟),而这里明确的直接使用了DateTime.Now,因此也可能违反了依赖倒置原则
如何解决呢?
其实并不复杂,咱们只要将方法内获取时间改成经过参数的形式传递进来好了
1 public string 当天时刻(DateTime time) 2 { 3 if(time.Hour >= 0 && time.Hour < 6) 4 { 5 return "晚上"; 6 } 7 if(time.Hour >= 6 && time.Hour < 12) 8 { 9 return "上午"; 10 } 11 if(time.Hour >= 12 && time.Hour < 18) 12 { 13 return "下午" 14 } 15 return "傍晚"; 16 } 17
这样作意味着什么呢?
意味着将时间的获取交给外部去处理,而方法内将只专一于处理“获取当天时刻”相关的主线逻辑,遵循单一职责
此时若是我要对这个方法进行测试的话就能够写出以下单元测试用例,且下述用例永远不会受到外部条件影响,只要”当天时刻”这个方法不出bug他永远该是对的就是对的
1 //简化代码,假设当天时刻是当前类里的静态方法,假设使用了Shouldly类库来作Assert 2 [Fact] 3 public void 上午九点_应该为上午() 4 { 5 当天时刻(new DateTime(2018,1,1,9,0,0)).ShouldBe("上午") 6 } 7 8 [Fact] 9 public void 下午三点_应该为下午() 10 { 11 当天时刻(new DateTime(2018,1,1,15,0,0)).ShouldBe("下午") 12 }
有了这个单元测试后,往后是否是想重构“当天时刻”这个方法也多了个保障,由于一旦你改错了,单元测试会诚实告诉你改出问题了
并且经过将代码改成“可测试”的,也将代码的优雅程度提升,使其遵循了单一职责,而且避免了违反依赖倒置原则
另外这个故事告诉咱们,小手一抖,就能违反n个原则。。。(隔壁家:不就改了个DateTime.Now嘛,怎么就搞出那么多有的没的)