单元测试理论知识问答

2010-03-02  张奇 

什么是单元测试?
    单元测试是针对代码单元的独立测试。从实用角度出发,“单元”是指函数, 以类为单元则过于复杂。“独立”是指将代码从原始项目中隔离出来,针对各个单元单独进行测试。

为什么需要单元测试?
    彻底测试:仅依靠系统测试会存在大量未覆盖的“死角”,单元测试可以实现代码级彻底测试,从根本上保证代码质量。
    成本最低:排错成本随时间推移和范围扩大直线上升,单元测试是最早阶段的测试,且目标最小,因此,排错成本最低。
    自动回归:单元测试将代码功能“定格”,代码修改后自动检查是否引入新的错误,避免陷入“系统测试->修改->引入新的错误->新一轮系统测试->修改->引入新的错误”的怪圈。自动回归也使开发过程适应频繁变更的需求,使开发过程自动“敏捷”。
    促进开发:利用单元测试还可以实现测试驱动开发和可视编程。可视编程使开发过程中程序行为可视,大幅提升开发效率、降低劳动强度。

单元测试的基本方法是?
    根据程序功能设定输入、执行测试、自动判断输出是否符合预期。测试过程需要以下关键元素:驱动(用于执行测试的代码)、用例(输入及预期输出)、桩(用于隔离耦合代码、或代替未实现代码)。

企业项目的单元测试面临哪些难点?
    测试简单独立的代码是很容易的,测试复杂项目则是另一回事。企业项目的单元测试面临以下难点:可测性问题、失真、不可控、静态局部变量的外部控制、内部输出的自动判断、复杂间接输入难于初始化、白盒覆盖逾后逾难等等。不解决这些难题。测试将无法进行,后面的条目将进一步阐述。

单元测试的具体目标是?
    单元测试是针对代码单元的独立测试,“独立”状态下易于发现的错误,都是单元测试的目标;集成后才易于发现的问题,则不是单元测试的目标。
    代码单元本身的功能错误都是单元测试的目标,而性能问题(时间性能如执行速度,空间性能如存储空间大小、内存泄漏)难于在最小单元内测试,不是单元测试目标。
    编码规范检查与单元测试无关,无论是否实施单元测试,编码规范检查都是必不可少的工作。
    静态分析属于全局扫描,严格来说也不是单元测试,提高编译器的警告级别,就是最简单高效的静态分析。
    单元测试是意义重大且困难的工作,目标应该具体而明确,将不属于单元测试的工作牵扯进来,其结果往往是“拣了芝麻,丢了西瓜”。
    选择工具时不要被“功能多多”所迷惑,要首先检查工具能否解决企业项目单元测试的难点,并用实际项目评估。“多”和“精”从来就是一对矛盾,要判断工具是不是因为无法解决单元测试的难题,故意把其他东西牵扯进来转移视线。

什么是测试用例?   
    测试用例就是程序功能的实例,对于单元测试来说,把函数功能明确化、实例化,用什么输入应该产生什么输出的形式记录下来,就是测试用例。

如何设计用例?
    根据功能点设定输入,再根据设计功能设定预期的正确输出,这样就构成了一个测试用例。
    通常,一个功能点对应一个等价类,“等价”是指测试效果上的等价,等价类中可能存在一个、多个或无数个值,取其中任何一个,如果测试通过,就表示同类中所有值都会测试通过。
    所谓“彻底测试”,是指等价类划分正确且完整,且设定了正确的预期输出,做到了这一点,代码可以保证不存在功能错误。

什么是测试驱动开发(TDD)?
    首先编写测试代码,然后编写产品代码,使编译和测试通过。
    优点:编写测试代码是一种设计行为,将程序功能细化、明确化;编程时目标具体而明确,避免多余动作;强制实施单元测试,避免编码后忽略测试。
    缺点:手工编写测试代码,比较费时;过于强调测试,很多代码是不需测试的,且往往在编写实现时才知道是否有必要测试;对编程过程的帮助不足,很多函数,都是在代码基本完成时,主要用例才能通过,在此过程中,TDD不能提供帮助;改变思维习惯,有些程序员难于接受。

什么是可视编程?   
    在编程过程中,程序行为可视。程序行为就是什么输入、执行哪些代码、产生了什么输出?
    可视编程由工具完成大部分工作,如生成桩、驱动、其他支持代码,人工只需要把功能细化、明确化并以用例形式记录下来;视需要测试,只有正在编写的代码逻辑复杂时才测试;程序行为可视,写几行代码就可以察看其行为,检验和调整编程思路,不必等到代码基本完成;不要求改变思维习惯。
    可视编程步骤:1)编写函数声明;2)设定最简单的输入和预期输出,自动生成测试代码;3)根据设计功能,列出其他输入,设定相应的预期输出;4)编写几行代码;5)执行测试,察看程序行为;6)重复4、5,直到绿条出现,编码和单元测试同步完成。

白盒、黑盒,白盒覆盖的局限与应用?
    白盒是指根据程序内部结构来设计用例,黑盒是指根据程序功能来设计用例。
    白盒方法可以精确统计覆盖状况,从而衡量完整性,但白盒覆盖只能基于现有代码,不能发现代码缺失。
    纯粹从白盒角度设计用例,叫做“跟着代码走”,即使完成了最高级别的覆盖率,测试员也可能还不了解代码应有的功能,更不用说检测功能是否正确,这种测试意义不大。
    用例应首先从功能角度来设计,然后根据覆盖状况找出遗漏用例,新加的用例仍然要根据功能设定正确的预期输出。

自动用例的局限与应用?
    自动生成用例是简单技术,但工具不可能自动了解代码功能,自动用例通常与功能无关,主要依赖自动用例是不现实的。
    自动用例可用于边界测试,即为边界输入自动生成用例,捕捉边界输入产生的异常、崩溃、超时等极端错误,这类错误通常是程序员未考虑边界输入,也未编写防御代码造成的,属于代码缺失,白盒覆盖难于发现。

企业项目单元测试关键点:隔离
    企业项目通常高耦合、可测性差。希望通过改进设计解决可测性问题是不现实的,程序是客观事物的反映,互相关联、互相纠缠不可避免。
    将测试目标从原始项目中隔离出来,这是测试的前提。隔离的主要方式是打桩。打桩必然造成失真,因此应避免不必要打桩。
    为减少工作量,应将个人的测试任务一次性隔离出来,任务以外的其他代码,关系紧密的应直接调用,关系松散的或未实现的自动打桩,库文件应直接调用。

企业项目单元测试关键点:用例
    与测试独立小程序不同,企业项目的用例设计将面对一些难题:打桩造成的失真、脱离原系统后部分底层代码行为不可控、静态局部变量无法外部初始化、复杂的间接输入难于初始化、内部输出难于自动判断等,这些是工具必须解决的。工具还应提供足够的灵活性,在特殊情况下可以人工处理。

企业项目单元测试关键点:效率
    效率决定实施能否成功。不要做平行、重复的事情,例如,没必要把黑盒方法和白盒方法分别做一遍、把动态方法和静态方法分别做一遍。
    使用合适的工具是提升效率的前提。驱动、打桩、插装、底层模拟支持、统计覆盖率、协助找出遗漏用例等等工作,都是工具可以完成也是必须完成的。
    工具的价值在于,解决人工难于解决的问题,提升效率,发挥人的智慧,而不是代替人的智慧。
    边开发边测试,例如测试驱动开发和可视编程,都是大幅提升效率的开发模式,尤其是可视编程,可以在不增加开发时间的前提下同时完成编码和单元测试。

企业项目单元测试关键点:效果
    与系统测试不同,针对具体单元,等价类是可穷举的,可以实现彻底测试,这也是需要单元测试的最主要原因,因此,应将彻底测试作为效果目标。
    彻底测试并不是指测试所有代码,逻辑简单的代码是没必要测试的。彻底测试是指覆盖被测函数的所有输入等价类。
    现实的思路是黑盒、白盒、自动相结合:1) 首先根据程序功能设计测试用例,可用分类集中法检验输入是否完整;2)根据白盒覆盖状况,为未覆盖的逻辑单位添加用例,实现高覆盖;3)执行自动生成的边界用例捕捉漏网之鱼。
417°/4080 人阅读/9 条评论 发表评论

关敏  2010-03-02

这个形式好,喜闻乐见


张奇  2010-03-02

关敏: 这个形式好,喜闻乐见
什么意思!你说排版啊?


关敏  2010-03-02

张奇: 什么意思!你说排版啊?
问答形式啊


张奇  2010-03-02

关敏: 问答形式啊
哦!呵呵!了解了嘎嘎


唐燕  2010-03-02

我认识的人就没有搞单元测试的,楼主是做单元测试的吗?我么这里好像单元测试都是开发人员自己做


张奇  2010-03-02

唐燕: 我认识的人就没有搞单元测试的,楼主是做单元测试的吗?我么这里好像单元测试都是开发人员自己做
我原来是学开发的!呵呵!是啊单元测试主要还是由开发人员的去做的!现在我的认识中测试人员做测试也是有很后的开发功底的呵呵!


唐燕  2010-03-02

张奇: 我原来是学开发的!呵呵!是啊单元测试主要还是由开发人员的去做的!现在我的认识中测试人员做测试也是有很后的开发功底的呵呵!
哦,


王艳  2010-03-05

我们这单元测试都由开发人员来做的


张奇  2010-03-05

王艳: 我们这单元测试都由开发人员来做的
嗯通常都是开发人员做的呵呵


登录 后发表评论