TDD in .NET Core - 简介

本文很多内容来自选自TDD实例一书。

预备知识

最好有一些预备知识,例如xUnit,Moq,如何编写易于测试的代码,这些内容我都写了文章:https://www.cnblogs.com/cgzl/p/9178672.html#test

Test Driven Development

什么是TDD(Test Driven Development)?

TDD是一个软件开发过程,这个过程依赖于重复性的小开发周期:需求被转化为具体的测试用例,然后改进程序以便通过测试。

在TDD里有两条规则:

  • 只在有未通过的自动化测试的情况下,你才会去写新的代码
  • 消灭重复

这两条规则在技术上的含义是:

  • 你必须进行良好的设计,运行的代码可在决策之间提供反馈
  • 开发人员得写自己的测试
  • 开发环境可以针对微小的变化需要提供快速的响应
  • 您的设计必须由众多高内聚、低耦合的组件组成,这样测试会更简单。

这两条规则也意味着编程的三个任务:

  1. Red - 先写一个不能工作/通过的小测试,甚至根本无法编译
  2. Green - 快速让这个测试通过,无论代码有多烂
  3. Refactor - 消除上个步骤中的代码重复。

RedGreenRefactor,这就是TDD的咒语。

如果TDD可以很好的执行,那么它就会大幅度减少代码缺陷的密度,也使工作的主题对于相关人员来说更加清晰。所以,TDD也具有社会含义:

  • 如果缺陷密度可以降低到足够的程度,那么QA就会从被动变为主动的工作。
  • 如果那些“让人讨厌的惊喜”可以减少到足够的程度,那么项目经理就可以精确的评估以便让客户参与到每日的开发工作中。
  • 如果技术会议的主题足够清晰,那么程序员就会按分钟去工作而不是按天或周来安排和进行工作。
  • 如果缺陷密度可以降低到足够的程度,那么我们每天都可以交付出具有新功能的软件,这就会与客户建立新的业务关系。

这些概念都很简单,但是动机是什么?为什么开发人员要去写自动测试代码?为什么开发人员在他们的思维能够大幅飙升的设计时,却只进行小步工作? 勇气

勇气

TDD是编程过程中管理恐惧的一种办法。

这个恐惧不是坏事,它是一种合理的恐惧,例如:”这个问题确实很难,我从开始的感觉看不到尽头“。

如果疼痛是喊的自然表达,那么恐惧就是告诉你要“小心”。

小心是很好的,但是恐惧还有一些其它的影响:

  • 让你不得不进行更多试探性操作
  • 让你交流的更少
  • 让你羞于反馈
  • 让你脾气暴躁

这些影响在开发的时候对你都没有任何帮助,尤其是遇到困难问题的时候。那么你如何面对困难处境并且:

  • 取代尝试/试探,而是尽快进行具体学习
  • 取代争吵,而是进行更清楚的沟通
  • 取代避免反馈,而是寻求帮助,和具体的反馈
  • 控制你自己的脾气

TDD会管理这些事情。

为什么要TDD

从业务角度:

  • 提供了需求的确认。通过编写测试以及RGR周期,需求确认很自然的在软件开发的过程中就完成了。
  • 捕获回归问题。回归问题就是指随着软件新功能的发布,以前的某些功能却不好用了。TDD可以很早的发现回归问题。
  • 综上两点,TDD也降低了维护成本。

从开发人员角度讲,TDD还有以下好处:

  • 设计为先的心态。写测试的时候,我们就得考虑与软件的交互应该如何实现,以便把这些功能需求编程可能。
  • 防止过度工程。关注于如何让测试通过和满足客户的期待,就会让我们保持正轨,而不是迷失于架构设计和幻想那么无法提供很多价值的最佳抽像设计中。
  • 增加开发人员的动力。取代了花费几天时间想尽办法来实现某个功能这样的操作,TDD把需求分解成一些测试,并结合RGR流程,这就允许你可以持续快速的进展并建立成功循环。
  • 收获自信。通过大量的测试结果,你感动支配的力量,无论修改、重构、增加功能都变得很简单。

第一个实例

在本例中,您将会看到TDD的如下步骤:

  1. 快速添加一个测试
  2. 运行所有的测试(包括以前写的),可以看到新添加的测试Fail了
  3. 修改一点代码
  4. 运行所有测试,都成功了
  5. 重构,移除重复

建立.NET Core 项目

这个很简单,首先建立一个Console App:

然后再添加一个xUnit项目:

这个测试项目需要引用Console项目。

需求

有这样一份报表:

现在想要做成支持多币种的:

这里还提供了汇率:

目标就是产生第二张图那样的报表。

开始操作

我们需要做哪些工作?

  • 让两种币种的钱数可以进行加法操作,并通过给定的汇率算出结果。
  • 让股票单价可以乘以股票数并得出总额。

上面是一个待办问题列表(To-Do List)。我们就关注于这个待办列表即可。

列表里的问题应该是逐个解决的,解决完一个划掉一个;如果有新问题,就在后边加上一条。

编写测试

下面我们开始,先不建立对象,先写测试

 让编译通过

这里有很多问题,编译也无法通过,这些问题我们也是一个一个来解决。

1. 首先,没有Dollar这个类,那就建立Dollar这个类:

第一个问题解决了。

2. 没有相应的构造函数,那就建立构造函数:

又解决了一个问题!

3. 没有Times()这个方法,那就建立该方法:

又解决了一个问题!

4. 没有Amount属性,建立该属性:

编译问题都解决了!!

看一下测试方法:

编译错误肯定是没有了。

测试Fail

然后跑测试:

不出意料肯定会Fail。

让测试通过

现在有了具体的这个Fail的测试,我们现在的任务就是让该测试变成Pass,而不是实现多币种报表,先让这个测试通过,再慢慢让其它测试通过。

您可能不喜欢这样,但是现在的目标不是做出完美的解决方案,目标就是让这个测试通过,所以这时候代码可能很烂:

我写死了数字10。

然后再跑测试:

测试Pass了!!

重构,移除重复

别着急,周期还没结束。

现在,我们需要移除重复。但是重复在哪?

通常你看到的重复是指代码的重复,这里是指测试中的数据和代码中数据的重复。

这个10是哪来的? 它实际上是:

是通过5乘以2得来的。

所以代码中的5*2和测试中的5*2是重复的。 我们需要移除这个重复,但是可能需要不止一步来实现。

先把乘法移动到Times方法里试试:

这样的话,测试仍然会pass:

这是一小步。

那么5是哪里来的?

应该是从构造函数传递进来的,我们可以把它存到Amount属性里:

所以我们可以在Times方法里使用它:

现在处理这个2,它应该可以使用参数multiplier代替:

OK!

此外,我们可以对代码的语法进行一些优化:

其实某些优化也应该通过TDD的RGR周期来实现。

第一篇文章就简单介绍这些。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏理论坞

互联网术语大全(一)

PM:Product Manager「产品经理」或 Project Manager 「项目经理」

1482
来自专栏Web项目聚集地

为什么你投了那么多家简历都石沉大海

为什么你投递了那么多家公司都石沉大海,和你本身的工作经验有关系,当然和你的简历书写也有很大关系。工欲善其事必先利其器,这是自古以来的道理,所以如果想找到一份好的...

2653
来自专栏生命的每一个角度

2018年5月2日,开始学习一门计算机语言

在此我会根据自己学习的进度,分享课程、文章、个人的一些见解和体会,让每一个像我一样的爱好者,参照入门。

3434
来自专栏hightopo

数百个 HTML5 例子学习 HT 图形组件 – WebGL 3D 篇

2172
来自专栏顾宇的研习笔记

讨论微服务之前,你知道微服务的 4 个定义吗?

关于“什么是微服务”的问题,其实并没有一个统一的认识。这些年在不同的场合里和不同背景的朋友都在探讨微服务。但聊得越多,就越发现大家聊的不是同一回事。和 Dev...

2673
来自专栏PPV课数据科学社区

【每日一课】R语言入门教程-1.3 R扩展包

课程名称:R语言入门教程 第一章:认识R 1.3 R扩展包 【课程目的】 在大数据时代里,数据分析愈发重要,R语言适合做数据分析,R语言已成为许多数据分析...

3819
来自专栏我是攻城师

Java在现实生活中都用在哪些项目?

4808
来自专栏编舟记

敏捷团队工作流

站会中的内容是每天工作的开始,也是对昨天工作的回顾。一般会由团队的某位成员主持,这位主持人有责任让电子系统上的story卡片和看板上的保持一致。站会上,大家依看...

2575
来自专栏ThoughtWorks

讨论微服务之前,你知道微服务的 4 个定义吗?| 洞见

关于“什么是微服务”的问题,其实并没有一个统一的认识。这些年在不同的场合里和不同背景的朋友都在探讨微服务。但聊得越多,越发现大家聊的不是同一回事。和 DevOp...

992
来自专栏程序你好

2018年我应该学习Java吗

我应该学习Java吗?这是一个不断出现的问题。如果你刚开始是一个开发人员,如果你已经是一个前端开发人员,或者即使你是一个。net背景的人,很多人都想知道学习Ja...

2283

扫码关注云+社区

领取腾讯云代金券