建议155:随生产代码一起提交单元测试代码

首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的版本稳定,性能也更差了,Bug似乎也变多了。也就是说,重构的代码看上去质量更高了,可实际测试结果却不如人意。

几乎每个程序员都因为此类问题纠结过。我们要修改的代码也许来自某些不负责任或经验欠佳的程序员,也许这些代码是自己一年前写的,但是看上去已经惨不忍睹。我们想要修改这些代码,却担心重构出别的问题。即便是一个开发周期中的产品,也会有这样的选择出现。某个模块可能已经提交测试并确认通过,不过现在发现有更优的算法和逻辑,改还是不改,成了一个问题。

“单元测试”减轻甚至消除了开发者这种恐惧。如果项目没有测试代码,说明我们只是生产“定时炸弹”。很多人将生产代码和测试代码分别对待,这是一种过时的做法。程序员在提交自己的生产代码时,必须同时提交自己的单元测试代码。很多现代化的版本管理工具可以在后台订制项目构建计划,自动运行测试项目,统计代码覆盖率,并生成相应报告。我们应该在早上一边喝咖啡,一边读取这样的报告。

有了测试代码做保证,在很大程度上我们可以放心去重构了。如果某个功能偏离了既有成果,就会有醒目的提醒。

将单元测试放在首要地位的一种开发模式是TDD模式。TDD(Test Driven Development测试驱动开发)有三条严格的定律:

  • 在编写不能通过测试的单元测试前,不要编写任何生产代码。
  • 只编写恰好无法通过的单元测试,不能编译也算不通过。
  • 只编写刚好足以通过当前失败测试的生产代码。

即使我们的团队没有完全采用TDD的开发模式,也可以借鉴这些定律来编写我们自己的测试代码。我们无需一次性编写完全部的测试代码,那没有必要,这跟过度设计一样,也不可能实现。事实上,我们应该逐步地编写测试代码,而且按如下步骤来编写:

测试代码->生产代码->测试代码

下面编写一个单元测试的例子:

先编写一个Add方法:

    public class SampleClass
{
public int Add(int a, int b)
{
return a + b;
}
}

右键创建单元测试:

VS会自动为我们生成一个测试方法:

        /// <summary>
///Add 的测试
///</summary>
[TestMethod()]
public void AddTest()
{
SampleClass target = new SampleClass(); // TODO: 初始化为适当的值
int a = ; // TODO: 初始化为适当的值
int b = ; // TODO: 初始化为适当的值
int expected = ; // TODO: 初始化为适当的值
int actual;
actual = target.Add(a, b);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("验证此测试方法的正确性。");
}

将方法修改成我们需要的方法就可以了:

        /// <summary>
///Add 的测试
///</summary>
[TestMethod()]
public void AddTest()
{
SampleClass target = new SampleClass(); // TODO: 初始化为适当的值
int a = 1; // TODO: 初始化为适当的值
int b = 2; // TODO: 初始化为适当的值
int expected = 3; // TODO: 初始化为适当的值
int actual;
actual = target.Add(a, b);
Assert.AreEqual(expected, actual);
Assert.Inconclusive("验证此测试方法的正确性。");
}

VS这个可视化测试工具太重量级了,导致开发的过程中运行测试代码太繁琐也太耗时。可以考虑用测试工具TestDriven.NET,这里不再介绍。

单元测试要注意一下几点:

首先,单元测试不应引入任何人机交互的内容。如,测试过程中不应该弹出对话框,等待用户输入或确认。单元测试不应该是被阻滞的。

其次,多线程也不属于单元测试范畴,单元测试应该是快速被执行的,而不是需要等待的。

最后,单元测试不应该跨应用程序域,例如,数据访问或者远程通信属于集成测试范畴,而不是单元测试。

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议[1-3]

    原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...

  2. 读书--编写高质量代码 改善C#程序的157个建议

    最近读了陆敏技写的一本书<<编写高质量代码  改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...

  3. 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试

    建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...

  4. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  5. 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣

    建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...

  6. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  7. 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释

    建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...

  8. 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量

    建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...

  9. 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法

    建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...

随机推荐

  1. 用户的 添加 权限 MySql远程登录

    添加一个用户 '; 为这个叫mongo的用户赋予操作z_0811数据库的所有权限 '; mysql如何修改开启允许远程连接   关于mysql远程连接的问题,大家在公司工作中,经常会遇到mysql数据 ...

  2. C++中结构体与类的区别 2

    这里有两种情况下的区别.(1)C的struct与C++的class的区别.(2)C++中的struct和class的区别.在第一种情况下,struct与class有着非常明显的区别.C是一种过程化的语 ...

  3. PHP中的traits简单理解

    Traits可以理解为一组能被不同的类都能调用到的方法集合,但Traits不是类!不能被实例化.先来例子看下语法: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 ...

  4. CocoStudio创建动画帧

    进入动画编辑器 选择“形体模式” 右键点击资源窗口的资源,可以进行删除,重命名的操作:  可以再资源窗口下方的预览窗口,查看选中的资源预览效果图: 右键点击“对象结构”,创建图层 选择“动画模式” 右 ...

  5. Julia - 算术基本函数

    符号函数和绝对值函数 abs(x) 函数求 x 的绝对值(幅值) julia> abs(3) 3 julia> abs(-3) 3 abs2(x) 函数求 x 的绝对值(幅值)的平方 ju ...

  6. Spring中application*的使用

    ApplicationAware 加载Spring配置文件时,如果Spring配置文件中所定义的Bean类实现了ApplicationContextAware 接口,那么在加载Spring配置文件时, ...

  7. leetcode705

    class MyHashSet { public: /** Initialize your data structure here. */ MyHashSet() { } void add(int k ...

  8. **请写出一段Python代码实现删除一个list里面的重复元素

    通常涉及到去重操作最好使用set,但是考虑到某些时候可能遇到不允许使用set的情况,那就自己实现一下: l = [2, 4, 5, 6, 1, 3, 4, 5] def f(l, b=0, c=1): ...

  9. OpenSUSE 安装JAVA环境变量JDK

    一.首先卸载虚拟机自带的JDK环境 具体命令: rpm -qa |grep java  --查找java信息 rpm –qa|grep jdk   --查找jdk信息 如果有依赖关系,提示无法卸载,使 ...

  10. notepad++正则表达式删除所有行某字符开始之前或者之后所有字符

    删除S 之后的所有字符用:s.*$ 删除S 之前的所有字符用:^.*s