初级测试开发面试题

自从我编写第一个单元测试以来已经有10年了。 从那时起,我不记得我已经编写了成千上万的单元测试。 老实说,我在源代码和测试代码之间没有任何区别。 对我来说是同一回事。 测试代码是源代码的一部分。 在过去的3-4年中,我与多个开发团队合作,并且有机会查看了大量的测试代码。 在这篇文章中,我总结了经验不足的开发人员在编写单元测试时通常会犯的最常见错误。

让我们看下面的类的简单示例,该类收集注册数据,对其进行验证并执行用户注册。 显然,该方法非常简单,其目的是演示单元测试的常见错误,而不是提供功能齐全的注册示例:

public class RegistrationForm {private String name,email,pwd,pwdVerification;// Setters - Getters are ommitted public boolean register(){validate();return doRegister();}private void validate () {check(name, "email");check(email, "email");check(pwd, "email");check(pwdVerification, "email");if (!email.contains("@")) {throw new ValidationException(name + " cannot be empty.");} if ( !pwd.equals(pwdVerification))throw new ValidationException("Passwords do not match.");}private void check(String value, String name) throws ValidationException {if ( value == null) {throw new ValidationException(name + " cannot be empty.");}if (value.length() == 0) {throw new ValidationException(name + " is too short.");}}private boolean doRegister() {//Do something with the persistent contextreturn true;}

这是注册方法的相应单元测试,有意显示单元测试中最常见的错误。 实际上,我已经看过很多次非常相似的测试代码,所以这不是我所说的科幻小说:

@Testpublic void test_register(){RegistrationForm form = new RegistrationForm();form.setEmail("Al.Pacino@example.com");form.setName("Al Pacino");form.setPwd("GodFather");form.setPwdVerification("GodFather");assertNotNull(form.getEmail());assertNotNull(form.getName());assertNotNull(form.getPwd());assertNotNull(form.getPwdVerification());form.register();}

现在,此测试显然将通过,开发人员将看到绿灯,所以竖起大拇指! 让我们转到下一个方法。 但是,此测试代码有几个重要问题。

在我拙见中,第一个是单元测试的最大误用是测试代码没有充分测试寄存器方法。 实际上,它仅测试许多可能路径中的一个。 我们确定该方法将正确处理空参数吗? 如果电子邮件中不包含@字符或密码不匹配,该方法将如何工作? 开发人员倾向于只为成功的路径编写单元测试,而我的经验表明,代码中发现的大多数错误都与成功的路径无关。 一个非常好的规则要记住的是,对于每一个方法,你需要N个测试,其中N等于在圈复杂度将所有私有方法调用的圈复杂度的方法。

接下来是测试方法的名称。 为此,我部分归咎于所有这些现代IDE,它们自动为测试方法(如示例中的方法)生成愚蠢的名称。 测试方法的命名应向读者解释将要测试的内容和条件 。 换句话说,它应该描述正在测试的路径。 在我们的情况下,更好的名称可能是: should_register_when_all_registration_data_are_valid。 在本文中,您可以找到几种命名单元测试的方法,但是对我来说,“应该”模式最接近人类语言,并且在阅读测试代码时更容易理解。

现在,让我们看一下代码的内容。 有几个断言,这违反了每个测试方法应断言一件事的规则 。 这一个断言了四(4)个RegistrationForm属性的状态。 这使得测试更加难以维护和阅读(哦,是的,测试代码应该像源代码一样可维护和可读。请记住,对我来说它们之间没有区别),并且很难理解测试的哪一部分失败。

此测试代码还声明了setter / getter。 这真的有必要吗? 为了回答这个问题,我将引用罗伊·奥什罗夫(Roy Osherove)的名言:“ 单元测试的艺术 ”

属性(Java中的getter / setter)是很好的示例代码,通常不包含任何逻辑,也不需要测试。 但是要当心:在属性中添加任何检查之后,您将要确保逻辑已经过测试。

在我们的案例中,设置器/获取器中没有业务逻辑,因此这些断言完全没有用。 此外,他们错了,因为他们甚至没有测试安装员的正确性。 想象一下,一个邪恶的开发人员将getEmail方法的代码更改为始终返回常量String而不是email属性值。 该测试仍将通过,因为它断言setter不为null,并且未断言期望值。 因此,这可能是您要记住的一条规则。 断言方法的返回值时,请始终尝试尽可能具体 。 换句话说,除非您不关心实际的返回值,否则请尽量避免使用assertIsNull,assertIsNotNull。

我们正在查看的测试代码的最后但并非最不重要的问题是,从未断言正在测试的实际方法( 寄存器 )。 它在测试方法内部被调用,但是我们从不评估其结果。 这种反模式的变化甚至更糟。 在测试用例中甚至不会调用被测方法。 因此,请记住, 不仅应该调用被测方法,而且还应该始终声明预期结果,即使它只是一个布尔值 。 有人可能会问:“无效方法是什么?”。 好的问题,但这是另一次讨论–可能是另一篇文章,但是为您提供一些提示,测试void方法可能会掩盖不好的设计,或者应该使用验证方法调用的框架(例如Mockito.Verify )来完成。

作为奖励,您应该记住这是一条最终规则。 想象一下, doRegister实际上已经实现,并且对外部数据库做了一些实际的工作。 如果某个本地环境中未安装数据库的开发人员尝试运行测试,将会发生什么情况。 正确! 一切都会失败。 确保测试即使从仅可访问代码和JDK的最垃圾终端运行,也具有相同的行为 。 没有网络,没有服务,没有数据库,没有文件系统。 没有!

翻译自: https://www.javacodegeeks.com/2014/09/common-mistakes-junior-developers-do-when-writing-unit-tests.html

初级测试开发面试题

初级测试开发面试题_初级开发人员在编写单元测试时常犯的错误相关推荐

  1. 初级开发人员在编写单元测试时常犯的错误

    自从我编写第一个单元测试以来已经有10年了. 从那时起,我不记得我已经编写了成千上万的单元测试. 老实说,我在源代码和测试代码之间没有任何区别. 对我来说是同一回事. 测试代码是源代码的一部分. 在过 ...

  2. 金九银十面试怒拿6个offer——测试开发面试题整理

    金九银十面试怒拿6个offer--测试开发面试题整理 1.软件测试的流程是什么? 2.测试用例主要有哪些元素? 3.软件测试有什么策略和阶段? 4.黑盒测试和白盒测试是什么?二者有什么区别? 5.软件 ...

  3. 吊打面试官系列之:常见测试开发面试题汇总,在面试的路上,总要先下手为强。

    测试开发面试题汇总 1.引言 2.热身题 3.理论基础 4.管理技能 5.服务端 7.移动APP 7.1 理论 7.2 实践 8.自动化测试 9.工具使用 10.算法 11.SQL 12.Linux ...

  4. 测试开发面试题(1)

    1.给你一个网站,你如何测试? 首先,查找需求说明.网站设计等相关文档,分析测试需求:制定测试计划,确定测试范围和测试策略,一般包括以下及部分,功能性测试.界面测试.性能测试. 数据库测试.安全性测试 ...

  5. 月薪1.5w,经常面试的测试开发面试题

    1.你在测试中发现了一个bug,但是开发经理认为这不是一个bug,你应该怎样解决? 首先,将问题提交到缺陷管理库进行备案. 然后,要获取判断的依据和标准: 根绝需求说明书,产品说明.设计文档等,确认实 ...

  6. 100道经典测试开发面试题,从基础到进阶(1)

    1.你在测试中发现了一个bug,但是开发经理认为这不是一个bug,你应该怎样解决? 首先,将问题提交到缺陷管理库进行备案. 然后,要获取判断的依据和标准: 根绝需求说明书,产品说明.设计文档等,确认实 ...

  7. 从基础到进阶,100道测试开发面试题,进大厂涨薪必备

    1.你在测试中发现了一个bug,但是开发经理认为这不是一个bug,你应该怎样解决? 首先,将问题提交到缺陷管理库进行备案. 然后,要获取判断的依据和标准: 根绝需求说明书,产品说明.设计文档等,确认实 ...

  8. python布尔测试对象_面试题十九期-测试开发面试题之python系列-这个中~

    坚持梦想 就算所有人都不支持你.这条路会很曲折,你也会一度认为是不是自己选错了,但只要坚持,就算最后没有成功,但努力了就不会有遗憾. 测试开发python系列面试题 01 单选题 1.下列哪个语句在P ...

  9. python测试开发面试题_python测试开发面试之深浅拷贝

    先来道题热热身 a = ('a', 'b','c') c = copy.copy(a) d = copy.deepcopy(a) if c == d: print("c和d的值相等" ...

最新文章

  1. Windows_Server_2008_R2_AD_DS架构-第06部分_FSMO、AD的诊断及排故
  2. 比特币分叉第一案,谁动了我的比特币现金?
  3. MBR区、DBR区、FAT区、DIR区和DATA区的区别
  4. 五万字 Linux 知识点深度解析,学完每个人都是高手
  5. 论如何优雅的处理回文串 - 回文自动机详解
  6. SCOI2010 股票交易
  7. Java学习---流与文件
  8. 面试官系统精讲Java源码及大厂真题 - 34 只求问倒:连环相扣系列锁面试题
  9. 浅谈C语言字符串结束符'\0'
  10. crnn pytorch 训练、测试
  11. 逆向破解必备基础smail基础语法
  12. Matlab影像像素坐标得到经纬度/经纬度转影像坐标(已知经纬度获取影像DN值)
  13. 主机内存测试软件,检测内存条的软件有哪些?内存条查看工具介绍
  14. 成功将qt程序移植到arm板上
  15. 7.10. RASP
  16. 李云赫天津大学计算机,祝贺创业谷涌现全国自强之星,同济创业谷,陪伴这个世上最有梦想的人...
  17. 如何查看当前Ubuntu的版本
  18. 电路中的电流采样IC选型
  19. 番茄炒鸡蛋里隐藏的九大秘密功效
  20. C#实现帮助文档CHM

热门文章

  1. P5290-[十二省联考2019]春节十二响【贪心,堆】
  2. 初一模拟赛(4.20)
  3. MST(最小生成树)上的确定性和存在性问题
  4. 01-MyBatis入门程序
  5. GatewayMetricsFilter网关度量过滤器(服务监控)
  6. 斐波那契查找+思路分析
  7. 生成方法中参数的注释
  8. c mysql 编码_mysql编码转换 mysql编码设置详解
  9. python定义函数prime判断是否是素数_用自定义函数判断素数 用C语言编写自定义函数prime(int x),判断x是否为素数?...
  10. (转)如何保障微服务架构下的数据一致性?