测试专员如何编写优秀的测试代码·单元测试篇
无论如何组织测试,无论有多少测试,如果你不能信任、维护以及阅读它们,这些测试就几乎没有价值。要成为优秀的测试,它们应该同时具有如下三个属性。
可靠性:开发人员希望运行的测试可靠,能够对测试结果有信心。可靠的测试没有缺陷而且测试正确的事情。
可维护性:无法维护的测试是梦,它们会拖延项目计划,或者当项目日程紧张时被搁置一旁。如果修改测试花费时间过多,或者经常需要为很小的产品代码频繁变更修改测试,开发人员会直接停止测试的维护和修复工作。
可读性:人们不仅要能够阅读测试,还要在测试出问题时找出症结所在。失去可读性另外两个支柱很快也会倒塌。如果无法理解测试,测试的维护工作就会变得困难,也无法得到人们的信任。
1. 可靠性
1.1 及时维护测试代码
测试代码与产品代码一样需要不断进行维护,一旦测试写好了并且通过了,通常是不应该修改或删除这些测试的。这些测试是你的保护网告诉你修改的代码是否破坏了已有的功能。虽说如此,有时可能还是需要修改或者删除已有的测试。要理解什么情况下修改或删除测试会带来问题,什么情况下这么做是合理的。
删除一个测试的主要的理由是这个测试失败了。如果一个测试突然开始失败,可能有如下原因:
• 产品缺陷被测试的产品代码有缺陷。
• 测试缺陷测试中有缺陷。
• 语义或者AP变更被测试代码的语义发生变化,但是功能不变
• 冲突或者无效的测试和测试相关的产品需求发生变化,产品代码随之变更
如果测试或代码没有任何问题,修改或删除测试的原因有:
• 重命名或者重构测试
不可读的测试带来的麻烦比解决的问题更多。它会影响代码的可读性,妨碍你理解测试发现的问题。
如果你看到测试名含义不清或者令人误解,或者测试的可维护性有待提高,就应该修改测试代码(但是不要改变测试的基本功能)。
• 去除重复代码
1.2 避免测试代码中的逻辑
如果单元测试中有下列任何一种语句,你的测试就包含了不应该有的逻辑:
• switch、if或e1se语句;
• foreach、for或whi1e循环。
包含逻辑的测试通常会一次测试多个东西,我们不推荐这种做法,因为这样的测试可读性较也比较脆弱。而且测试逻辑也增加了代码复杂度,可能包含隐藏的缺陷通常来说,一个单元测试应该是一系列的方法调用和断言,但是不包含控制流语句,甚至不应将断言语句包含在try- catch中。任何更复杂的语句都可能导致如下问题。
• 测试难以阅读和理解
• 测试难以重现。(设想一下,如果一个多线程测试或者使用随机数的测试突然失败了,该如何处理。)
• 测试较容易包含缺陷或者测试错误的事情
• 难以命名测试,因为它执行多件任务
1.3 只测一个关注点
如前所述,一个关注点是一个工作单元的一个最终结果:一个返回值、系统状态的一个改变或者对第三方对象的一个调用。例如:如果你的单元测试对多个对象进行了断言,那么这个测试有可能测试了多个关注点。另一种情况是,它既测试了一个对象返回正确的值,又验证系统状态改变导致这个对象的行为发生变化,那么这个测试也可能测试了多个关注点。
测试多个关注点听起来没什么,但是等到你要命名测试,或者考虑第一个对象的断言失败该如何处理时,就会遇到问题。
命名测试看似简单,但是如果同时测试了多个东西,就几乎不可能给测试起一个能说明测试内容的好名字。你最后起的名字可能非常通用,使得读者不得不去阅读测试代码(本章的可读性节详细对此进行讨论)。如果一次只测试一个关注点,测试命名就很简单。
1.4 单元测试与集成测试分离
把集成混在单元测试里放在测试项目中会导致很多方面的问题。这种测试难以运行,会让人们误以为代码有问题,浪费时间和精力进行检查,最后导致开发人员不再信任这组测试。混在单元测试里的集成测试就像筐里的烂苹果连累了其他的测试。如果下一次再发生类似的事情,开发人员甚至都不会去调查失败原因,直接就说:“哦,那个测试有时候就是会失败,没事的。”要避免这样的事情发生,就要建一个绿色安全区把集成测试和单元测试分开。
绿色安全区里只包含单元测试。运行绿色安全区里的所有测试测试结果应该全部是绿色的,如果有测试失败,就说明出现了真正的代码问题,而不是因为某些配置或外部依赖倒置的假警报。
1.5 代码审查与覆盖率结合
代码覆盖率100%说明什么呢?如果没有做代码审查,这个覆盖率不能说明什么。你的团队可能会要求所有人的测试“达到95%以上的代码覆盖率”,大家可能也确实做到了。但是也许这些测试连断言都没有。人们通常会选择做最少的事情达到某个指定的目标。
那么代码覆盖率100%再加上测试和代码审查能说明什么呢?这说明整个世界都是你的。如果你做了代码审查和测试审查,确保测试优秀而且覆盖了所有代码,那么你就拥有了一个安全网,可以避免愚蠢的错误,同时团队也获得了分享的知识,从持续的学习中获益。
2. 可维护性
2.1 去除重复(Extract Method)
作为开发者,单元测试中的重复代码和产品代码中的重复一样(如果不是更加)有害。DRY原则应该同样适用于测试代码。重复代码意味测试对象某方面改变时要修改更多的测试代码。如果测试中有大量重复代码,构造函数变更或者使用类的语义变化会产生极大的影响。
2.2 测试隔离
测试隔离的基本概念是:一个测试应该总是在它自己的小世界中运行,与其他进行类似或不同的工作的测试隔离甚至不知道其他测试的存在。
如果没有很好地隔离测试,它们会互相影响,使你非常悲惨,后悔在项目中尝试单元测试决心以后再也不做单元测试了。我见过这种情况。开发人员不愿费心检查测试中的问题,因此当出现问题时,需要花很多时间才能找到原因有些测试同样存在着一些坏味道能够提示测试隔离可能有问题。
• 强制的测试顺序测试需要以某种特定顺序执行,或者需要来自其他测试结果的信息。
• 隐藏的测试调用测试调用其他测试。
• 共享状态损坏测试共享内存里的状态,却没有回滚状态。
• 外部共享状态损坏集成测试共享资源,却没有回滚资源。
2.3 避免对不同的关注点多次断言(使用参数化测试)
Assert.AreEqual(2,Sum(1,2));
Assert.AreEqual(5,Sum(2,2));
Assert.AreEqual(6,Sum(5,2));
如上示例,这个测试方法中使用了三个断言,进行了三个测试。这样看起来在实际过程中会节省一些写代码的时间,但会有一些问题。如果第一个断言失败,则后续断言就不会再执行。而在这个示例中我们是进行了三个测试。第一个断言失败就会导致我们无法得知另外两个测试的测试结果。对于这种情况我们可以采取别的方式进行测试
1)给每个断言创建一个单独的测试。
2)使用参数化测试。
3)把断言代码放在一个try-catch块中。
2.4 避免过度指定
过度指定的测试对一个具体的被测试单元如何实现其内部行为进行了假设,而不是只检查其最终行为的正确性单元测试中过度指定主要有以下几种情况:
• 测试对一个被测试对象的纯内部状态进行了断言
• 测试使用多个模拟对象
• 测试在需要存根时使用模拟对象
• 测试在不必要的情况下指定顺序或使用了精确匹配
3. 可读性
不可读的测试几乎没有任何意义。可读性这条线连接着编写测试的人和几个月后阅读测试的人。测试是你向项目的下一代开发者讲述的故事,帮助开发者理解一个应用程序的组成及其开端。
测试可读性有如下几个方面:
• 命名单元测试
• 命名变量
• 使用好的断言信息
• 把断言和操作分离
3.1 单元测试命名
命名标准非常重要,提供了合理的规则和模板,列出应该包括的测试信息。测试名一般包括三部分。
被测试方法名,非常关键,指明了被测试逻辑的位置。把被测试方法名放在测试方法开头,可以很容易地在测试类中浏览测试和使用智能感知(如果IDE支持)。
测试场景,说明了测试使用的条件:“如果我用一个nu11值调用方法x,那么它应该执行Y。”
预期行为,基于当前场景,方法应该产生的行为结果或者返回值,或者行为方式:“如果用一个null值调用方法X,那么它应该执行Y。”如果测试名缺少上面列出的任何一部分,测试的读者就会疑惑测试究竟在做什么,需要阅读测试代码。合理地命名测试,主要目的就是为了使后来的开发者从为了理解测试而阅读代码的负担中解脱出来。
public void IsValidFileName(){...}[Test]public void
IsValidFileName_WhenPNG_ReturnFalse(){...}
如上示例,通过测试的方法命名我们就可以大概知道要测试的是方法是IsValidFileName当输入参数是PNG的时候,预期返回False。
当然,你的团队也可以有适合自己的命名方式,但重要的是如果一个团队中都有统一的有意义命名规范,那么单元测试的可读性将大大提升,并且有利于后来者快速进入项目,理解测试。
3.2 变量命名
测试中的变量命名和产品代码中的命名规范同样重要,通过合理的变量命名,我们可以确保阅读测试的人可以尽快的理解你要验证什么。
// 反例Assert.AreEqual(100,actual);
如上示例,我们经常会看到测试中出现"100"这样的魔法数字。因为测试中没有描述性的名字,也许你在刚刚写完的时候还知道它是什么意思,但是一周后,一月后,一年后呢?甚至你未来的继任者看到这样的测试代码也是一头雾水。
3.3 断言和操作分离
很多人为了“偷懒”经常会把断言和方法调用卸载同一行里,但这是一个很不好的习惯,它会大大降低代码的可读性。
// 反例Assert.AreEqual(true,fileManger.IsValidName())// 正例bool expect=true;bool actual=fileManger.IsValidName();Assert.AreEqual(expect,actual)
最后: 可以关注公众号:伤心的辣条 ! 进去有许多资料共享!资料都是面试时面试官必问的知识点,也包括了很多测试行业常见知识,其中包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。
好文推荐
转行面试,跳槽面试,软件测试人员都必须知道的这几种面试技巧!
面试经:一线城市搬砖!又面软件测试岗,5000就知足了…
面试官:工作三年,还来面初级测试?恐怕你的软件测试工程师的头衔要加双引号…
什么样的人适合从事软件测试工作?
那个准点下班的人,比我先升职了…
测试岗反复跳槽,跳着跳着就跳没了…
测试专员如何编写优秀的测试代码·单元测试篇相关推荐
- 怎样编写测试类测试分支_编写干净的测试–天堂中的麻烦
怎样编写测试类测试分支 如果我们的代码有明显的错误,我们很有动力对其进行改进. 但是,在某些时候,我们认为我们的代码"足够好"并继续前进. 通常,当我们认为改进现有代码的好处小于所 ...
- 怎样编写测试类测试分支_编写干净的测试-被认为有害的新内容
怎样编写测试类测试分支 很难为干净的代码找到一个好的定义,因为我们每个人都有自己的单词clean的定义. 但是,有一个似乎是通用的定义: 简洁的代码易于阅读. 这可能会让您感到有些惊讶,但我认为该定义 ...
- 怎样编写测试类测试分支_编写干净的测试–从配置开始
怎样编写测试类测试分支 很难为干净的代码找到一个好的定义,因为我们每个人都有自己的单词clean的定义. 但是,有一个似乎是通用的定义: 简洁的代码易于阅读. 这可能会让您感到有些惊讶,但我认为该定义 ...
- java算术测试软件_Java——编写一个算术测试小软件
问题描述: 编写一个算术测试小软件,用来训练小学生的算术能力.程序由3个类组成,其中Teacher类对象负责给出算术题目,并判断回答者的答案是否正确:ComputerFrame类对象提供的GUI界面看 ...
- python压力测试模块_Python编写服务器压力测试小工具(仅供测试)
想知道你的网站能支持多少用户一起访问吗?想知道你的网站在遭遇DDOS时能坚持多长时间嘛? 此文章只适用于Apache服务器,不适用于Nginx及其它服务器.考虑到Apache服务器的特性,一个连接对应 ...
- 编写干净的测试–天堂中的麻烦
如果我们的代码有明显的错误,我们很有动力进行改进. 但是,在某些时候,我们认为我们的代码"足够好"并继续前进. 通常,当我们认为改进现有代码的好处小于所需的工作时,就会发生这种情况 ...
- 软件测试(软件测试生命周期,描述一个bug,定义bug级别,bug生命周期,如何开始第一次测试,测试执行和bug管理,测试工作中的人际关系处理)
一.软件测试的生命周期 对比软件的生命周期和bug的生命周期 · 软件的生命周期:需求分析--计划--设计--编码--测试--运行维护 · 软件测试的生命周期:需求分析--测试计划--测试设计.测试开 ...
- 测试私有方法 重构_通过测试学Go:指针和错误
点击上方蓝色"Go语言中文网"关注我们,领全套Go资料,每天学习 Go 语言 你可以在这里找到本章的所有代码[1] 我们在上一节中学习了结构体(structs),它可以组合与一个概 ...
- 软件测试整理一:测试基础知识以及开发、测试模型、按照开发阶段进行测试
文章目录 一.基础概念 1.什么是软件测试 2.软件测试的目的 3.软件测试的原则 4.软件测试的分类 4.1 按照开发阶段分类 4.2 按照软件特性分类 4.3 按照测试技术分类 4.4 按照测试运 ...
最新文章
- ETSI MEC — 网业协同架构
- 火焰效果材质实现_利用噪音图制作一个纸张燃烧的效果
- 【Jetson Nano学习笔记】1. 系统镜像和ROS的安装
- Eclipse中使用Checkstyle,checkstyle插件检查java代码的自定义配置文件:
- php arcsin,三角函数在线计算器
- InVEST模型(生态系统服务)
- 互联网名词解释(通用、运营、广告、APP推广、移动推广、APP运营、商务模式、职位、客户管理)
- git的版本回溯(git想要退回到之前写过的某一个版本)
- Excel·VBA考勤打卡记录统计结果
- steer clear of用法
- 大数据时代,个人信息安全由谁来保护?
- 项目管理体制改革的经验和成效(转)
- 2022 年十大绩效考核技巧
- 测试网站速度的8款免费工具推荐
- 星期一到星期日的英文 缩写 读音 巧记方法
- erlang 学习ets表-2
- 苹果html 闪退,iPhone6 App闪退的解决办法 掌握这4点苹果App不再闪退
- 手把手接入高德地图API——POI周边搜索功能实现
- 未来属于智能,智能存在未在每个角落-称重
- 今天兼职的那份工作,安排了休息
热门文章
- 可以进行单元测试么_大量实例助攻,让你的单元测试更高效
- git 第二次提交_win10 将本地项目上传到github (第一次+再次上传)
- python os 遍历 子目录中所有文件_Python处理文件系统的10种方法 !
- java8 两个list合并_深入介绍和使用 Java 8 的 Collector 接口和 Collectors 工具类
- visual studio odbc数据源设计器_商业智能BI应该支持哪些类型的数据源?
- mysql数据库和表的关系_MySQL数据库学习【第六篇】表与表之间的关系
- 以太网口差分电平_高速串行总线设计基础(八)揭秘SERDES高速面纱之CML电平标准与预加重技术...
- 用智能墨水打造超灵敏传感器 “写”到哪里感知就到哪里...
- LOCAL_SHARED_LIBRARIES 与 LOCAL_LDLIBS,LOCAL_LDFLAGS的区别
- Objective-C:内存管理的小结