TDD中的单元测试写多少才够

测试驱动开发(TDD)已经是耳熟能详的名词,既然是测试驱动,那么测试用例代码就要写在开发代码的前面。但是如何写测试用例?写多少测试用例才够?我想大家在实际的操作过程都会产生这样的疑问。

3月15日,我参加了thoughtworks组织的“结对编程和TDD Openworkshop”活动,聆听了tw的资深咨询专家仝(tong2)键的精彩讲解,并在讲师的带领下实际参与了一次TDD和结对编程的过程。活动中,仝键老师对到底写多少测试用例才够的问题,给出了下面一个解释:

我们写单元测试,有一个重要的原因是用来防止自己犯低级错误的。我们不能把写实现代码的人当作我们的敌人,一定要把全部情况都测到,以防止他们在里面故意留下各种隐蔽的陷阱。测试写的再多可能也没有办法覆盖全部情况,所以只要能让自己感到安全即可。怎样才能让自己感到安全呢?这是没有标准答案的,只能是写多了测试以后慢慢体会。

另外,写测试也要花时间的,比如compare这个方法的实现部分,我们只花了一两分钟就写完了,而这些测试代码,我们花了足足半个多小时,这样做值得吗?对于简单的业务逻辑来说,当然是不值得的,毕竟我们还很多工作等着做,老板花钱是为了我们的产品代码,而不是测试代码。

再考虑一种情况,我要创业,想了一个点子,做了一个网站,我当然是想以最快的速度把它做成型让别人用。如果我在完全不知道人们会不会喜欢的时候,先花大量时间写测试,最后发现没人用只能丢掉,这些测试岂不是白写了。

所以还是上面那句话:单元测试是让你提升自己对代码的信心的,只要你感觉安全可以继续开发时就够了,不是越多越好。

我相信上面一段解释对于本文中提出的问题大家都没有什么异议。但是这里我们不考虑特殊情况,在实际操作中,是否有办法对单元测试这一工作进行衡量?来判断是否足够?

使用代码覆盖率来衡量单元测试是否足够

常见的代码覆盖率有下面几种:

语句覆盖(Statement Coverage):这是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了。

判定覆盖(Desicion Coverage):它度量程序中每一个判定的分支是否都被测试到了。

条件覆盖(Condition Coverage):它度量判定中的每个子表达式结果true和false是否被测试到了。

路径覆盖(Path Coverage):它度量了是否函数的每一个分支都被执行了。

前三种覆盖率大家可以查看下面的引用的第3篇文章,这里就不再多说。我们通过一个例子,来看看路径覆盖。比如下面的测试代码中有两个判定分支

int foo(int a, int b)
{
    int nReturn = 0;
    if (a < 10)
    {// 分支一
        nReturn+= 1;
    }
    if (b < 10)
    {// 分支二
        nReturn+= 10;
    }
    return nReturn;
}

我们仔细看看逻辑,nReturn的结果一共有4种可能,我们通过路径覆盖的方法设计出来的测试用例:

Perfect。但是实际中的代码往往比上面的例子复杂,如果代码中有5个if-else,那么按照路径覆盖的方法,至少需要25=32个测试用例。这样简直要疯掉了。

没必要追求代码覆盖率,真正要覆盖的是逻辑

简单追求代码结构上的覆盖率,容易导致产生大量无意义的测试用例或者无法覆盖关键业务逻辑。我们再看看上面解释的第一段话。

我们写单元测试,有一个重要的原因是用来防止自己犯低级错误的。我们不能把写实现代码的人当作我们的敌人,一定要把全部情况都测到,以防止他们在里面故意留下各种隐蔽的陷阱。测试写的再多可能也没有办法覆盖全部情况,所以只要能让自己感到安全即可。怎样才能让自己感到安全呢?这是没有标准答案的,只能是写多了测试以后慢慢体会。

怎么才算让自己感到安全?覆盖逻辑,而不是代码。站在使用者的角度考虑,需要关心的是软件实现逻辑,而不是覆盖率。如下面的例子:

public class UserBusiness
    {
        public string CreateUser(User user)
        {
            string result = "success";

            if (string.IsNullOrEmpty(user.Username))
            {
                result = "usename is null or empty";
            }
            else if (string.IsNullOrEmpty(user.Password))
            {
                result = "password is null or empty";
            }
            else if (user.Password != user.ConfirmPassword)
            {
                result = "password is not equal to confirmPassword";
            }
            else if (string.IsNullOrEmpty(user.Creator))
            {
                result = "creator is null or empty";
            }
            else if (user.CreateDate == new DateTime())
            {
                result = "createdate must be assigned value";
            }
            else if (string.IsNullOrEmpty(user.CreatorIP))
            {
                result = "creatorIP is null or empty";
            }

            if (result != "success")
            {
                return result;
            }

            user.Username = user.Username.Trim();
            user.Password = BitConverter.ToString(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(user.Password)));

            UserDataAccess dataAccess = new UserDataAccess();
            dataAccess.CreateUser(user);

            return result;
        }
    }

更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/project/

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索测试
, 单元测试
, 代码
, result
, user
, 覆盖率
自己写代码
tdd测试驱动开发、tdd测试驱动开发教程、tdd测试驱动开发实例、tdd 失败 测试、tdd 优缺点 测试,以便于您获取更多的相关知识。

时间: 2025-01-23 15:13:50

TDD中的单元测试写多少才够的相关文章

Visual Studio 中的单元测试 UNIT TEST

原文:Visual Studio 中的单元测试 UNIT TEST 注:本文系作者原创,可随意转载,但请注明出处.如实在不愿注明可留空,强烈反对更改原创出处. TDD(Test-Driven Development) 测试驱动开发是敏捷开发中的一项核心实践和技术,也是一种设计方法论.TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码.单元测试是最基本的测试步骤.位于整个产品开发流程V模型的最底部.大致如图,在各种开发流程中RA&PSD完成后,无需底层基础,

在Python的Flask框架中实现单元测试的教程

  在Python的Flask框架中实现单元测试的教程,属于自动化部署的方面,可以给debug工作带来诸多便利,需要的朋友可以参考下 概要 在前面的章节里我们专注于在我们的小应用程序上一步步的添加功能上.到现在为止我们有了一个带有数据库的应用程序,可以注册用户,记录用户登陆退出日志以及查看修改配置文件. 在本节中,我们不为应用程序添加任何新功能,相反,我们要寻找一种方法来增加我们已写代码的稳定性,我们还将创建一个测试框架来帮助我们防止将来程序中出现的失败和回滚. 让我们来找bug 在上一章的结尾

在 MVP 中进行单元测试

对于测试,大家都不陌生,但是我相信还是有部分开发觉得测试工作和自己没有直接关系.测试工作是测试工程师的事.惭愧的说,本人也是很长一段时间内没真正理解"测试"这件事儿,之前呆过的几家公司都没有真正的"测试工程师",确切的说,是没有会写代码的测试工程师,基本上都是手动测试,然后输出报告,测试无需懂技术,我相信国内很多公司都是这样,特别是 App 端的测试,很少有白盒测试的.这篇要说的东西不多,主要来说说单元测试,由于本人也是最近才开始实践,文章抛砖引玉,如果有说得不到位

settings-orcal 中存储过程 这样写对吗

问题描述 orcal 中存储过程 这样写对吗 create or replace procedure PageList(tbName IN VARCHAR(255),tbFieldsIN VARCHAR(1000), orderField IN VARCHAR(255),orderType IN INT,strWhere IN VARCHAR(1000),pageSize IN INT,pageIndex IN INT,pageRecord OUT INT) is BEGIN /*定义变量*/

在asp/asp.net中调用java写的类

asp.net|asp.net 在开发过程中偶尔会遇到要在ASP/ASP.Net中调用JAVA写的类,以实现之前已经用JAVA实现的功能,下面就以一个简单示例说明详细的使用方法: 1.创建java文件:使用任何你喜欢的编辑器编辑以下内容:public class hello{ public String helloWorld(String s) { if(s == null) return ""; else return s; }}将此文件保存为hello.java 2.编译java文

怎样在C#中调用Delphi6写的DLL

我在编写一个系统时遇到了一个问题,无法在C#中调用Delphi6写的DLL,只因为DLL的参数是string类型的.然后在网上找相关的资料,还是没有结果.经过我的再三琢磨,现在已经解决,特写此文章与大家分享我的喜愉!Dellphi DLL文件:///////////////////////////////////////////////////////////////////library mydll; uses SysUtils, Classes; {$R *.res}function Out

在网页中调用VC写的对话框

要想在网页中调用VC写的对话框,那就得创建一个OCX了,下面将一步一步教你怎么写OCX: 第一步选择"MFC ActiveX ControlWizard",写入创建工程的名字,然后一路狂按"NEXT",直到"Finish",至此一个简单的MFC型的OCX框架已完成了; 第二步在资源中添加一对话框,并创建一个对话框的新类; 第三步就得为OCX添加方法了,见图:ClassWizard->Add Method,选择OK: 接着给方法添加以下代码:

iOS开发中的单元测试(二) 让断言活泼起来的匹配引擎

上一篇文章简单介绍了OCUnit和GHUnit两款iOS开发中较为常见的单元测试框架,本文进一步介绍单元测试 中的另一利器--匹配引擎(Matcher Engine).匹配引擎可以替代断言方法,配合单元测试引擎使用,测试 用例可以更多样化,更细致. 传统断言提供的方法数量和功能都有限,以导读中提到的两款框架为例 ,即使是断言相对丰富的GHUnit也只是提供了38种断言方法,范围仅涵盖了逻辑比较,异常和出错等少数几方 面,仍然很单一.而使用匹配引擎代替断言,可能性就大大丰富了,除了普通断言支持的规

在Word中整理笔记页中的手写内容的方法

在Word中整理笔记页中的手写内容的方法   图1 OneNote中的手写内容 在OneNote 2007中,打开需要导入到Word中的笔记页,然后,执行菜单栏中的[文件]|[发送至]|[Microsoft Office Word]命令(如图2所示),即可将手写内容转换为标准的文本并发送到Word中,这样就可以对其进行相关排版.打印等操作了,如图3所示. 图2 执行菜单栏中的[文件]|[发送至]|[Microsoft Office Word]命令