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

初级测试开发面试题

自从我编写第一个单元测试以来已经有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

初级测试开发面试题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/339738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用SoapUI调用安全WCF SOAP服务–第1部分,该服务

在这个由三部分组成的传奇中,我将演示如何使用SoapUI API工具来调用安全的SOAP服务。 首先,我将专注于创建服务,在接下来的文章中它将充当被测系统。 使用基本身份验证传输安全性机制维护对该服务中资源的访问。 Windows Communication Foun…

java简单系统_Java简单学生管理系统

Java简单学生管理系统这个不需要手动输入,笔记记录//studentpublic class student(){private String id;//学号private String name;//姓名private int age;//年龄public String getId() {return id;}public void setId(String id) {this.id id;}public String get…

kafka java编程demo_Kafka简单客户端编程实例

今天,我们给大家带来一篇如何利用Kafka的API进行客户端编程的文章,这篇文章很简单,就是利用Kafka的API创建一个生产者和消费者,生产者不断向Kafka写入消息,消费者则不断消费Kafka的消息。下面是具体的实例代码。一、创…

java我的世界极限生存_我的世界 1.7.10 极限生存整合包

整合包介绍:最近总有人觉得Minecraft很无聊,没有什么可玩的,或者觉得生存太简单 那么就来试试这个吧,全部是增强怪物的MOD,保证不无聊,保证不简单 基本上没有增加一些新的东西,只增加了几种怪物…

具有InlfuxDB的Spring Boot和Micrometer第1部分:基础项目

对于那些关注此博客的人来说,难怪我倾向于大量使用InfluxDB。 我喜欢这样一个事实,它是一个真正的单一用途的数据库(时间序列),具有许多功能,并且还带有企业支持。 Spring也是我选择的工具之一。 因此&…

PIT,JUnit 5和Gradle –仅需额外的一行配置

在Gradle(带有gradle-pitest-plugin 1.4.7)中发现简单,经过改进的PIT和JUnit 5配置。 不可否认,如今JUnit 5越来越受欢迎。 虽然为JUnit 5提供了一个专用于PIT的插件,并且gradle-pitest-plugin支持了很多年&#xff0…

apache camel_使用WildFly 8在Java EE7中自举Apache Camel

apache camel从Camel版本2.10开始,支持CDI(JSR-299)和DI(JSR-330)。 这为在Java EE容器中以及在独立的Java SE或CDI容器中开发和部署Apache Camel项目提供了新的机会。 是时候尝试一下并熟悉它了。 骆驼到底是什么&am…

Hibernate中保存与持久性以及saveOrUpdate之间的区别

保存与保存或更新与持久保存在Hibernate中 save和saveOrUpdate之间的区别是什么或save和persist之间的区别是任何Hibernate面试中常见的面试问题,就像Hibernate中get和load方法之间的区别一样。 Hibernate Session类提供了几种方法,可以通过诸如save&am…

java中的语句有哪些_java中的循环语句有哪些

Java中有三种主要的循环结构:while 循环do…while 循环for 循环顺序结构的程序语句只能被执行一次。如果您想要同样的操作执行多次,,就需要使用循环结构。一、while循环语法:while( 布尔表达式 ) {     //循环内容   }只要符合布尔表达…

php无法新数据类型,新手入门PHP必知的七种数据类型

想要入门PHP,首先要学会搭建环境,其次是学习基础语法。PHP的基础包括数据类型,运算符,变量和常量等。在这篇文章中,我们主要了解什么是数据类型。数据类型是指同种数据的一个统称,一般会描述为XX数据类型。…

攻防世界web高手进阶php_rce,php_rce 攻防世界xctf web

php_rce首先了解ThinkPHP5.x rec 漏洞分析与复现https://blog.csdn.net/qq_40884727/article/details/101452478var_pathinfo的默认配置为s,我们可以通过$_GET[‘s’]来传参于是构造payloadhttp://111.198.29.45:30600/index.php?sindex/\think\App/invokefunction&functi…

具有InlfuxDB的Spring Boot和Micrometer第2部分:添加InfluxDB

自从我们添加了基本应用程序以来&#xff0c;是时候启动InfluxDB实例了。 我们将按照之前的教程进行操作&#xff0c;并添加一个docker实例。 docker run –rm -p 8086&#xff1a;8086 –name influxdb-本地influxdb 是时候在我们的pom上添加微米InfluxDB依赖项了 < dep…

使用比较器的nulls对具有null值的列表进行排序

你好朋友&#xff0c; 在本教程中&#xff0c;我们将看到如何使用Java 8 Comparator.nullsFirst在列表中的项目很少为空时如何对项目列表进行排序&#xff0c;以便将null视为列表中的最小元素。 –什么是比较器 – nullsFirst方法在Comparator中做什么 –排序具有非空名称的…

Jar Hell变得轻松–用jHades揭开类路径的神秘面纱

Java开发人员将不得不面对的最困难的问题是类路径错误&#xff1a; ClassNotFoundException &#xff0c; NoClassDefFoundError &#xff0c;Jar Hell&#xff0c; Xerces Hell和公司。 在本文中&#xff0c;我们将探究这些问题的根本原因&#xff0c;并了解最小的工具&#…

分度器中硒定位器的完整指南(示例)

在测试网站的功能时&#xff0c;特别是Web元素&#xff08;例如单选按钮&#xff0c;文本框&#xff0c;下拉列表等&#xff09;&#xff0c;您需要确保能够访问这些元素。 Selenium定位器正是出于这个目的&#xff0c;通过使用此命令&#xff0c;我们可以识别这些Web元素DOM&a…

wildfly管理控制台_WildFly 9 –别希望您的控制台像这样!

wildfly管理控制台每个人都可能听到这个消息。 周一发布了第一个WildFly 9.0.0.Alpha1版本。 您可以从wildfly.org网站上下载它&#xff0c;最大的变化是它是由一个新的功能配置工具构建的&#xff0c;该工具位于现在单独的核心发行版上&#xff0c;还包含一个新的Servlet发行版…

azure mysql sql,UiPath连接Azure Sql Server数据库

一、创建数据库在Azure中创建SQL数据库image更改防火墙设置&#xff0c;并设置客户端IP访问规则image二、安装数据源驱动在本地安装数据源驱动程序&#xff0c;保证可以正常接入到远程的数据库。如果不安装驱动程序&#xff0c;则会出现以下报错&#xff1a;[Microsoft][ODBC D…

linux 误删除mysql表能恢复吗,Linux误删数据恢复

引子指在键上飘&#xff0c;难免会湿手套。当你按下shiftdel键后&#xff0c;会不会突然心里凉透&#xff0c;当你执行rm -rf后&#xff0c;会不会马上去搜索哪个国家入境不需要签证。或者你还会遇到如下的情况&#xff1a;root4xem7:~# aliasalias cdrm -rfalias ddocker数据恢…

Apache Camel 3.1 –更多骆驼核心优化(第3部分)

我以前曾在博客中介绍过我们在下一个Camel 3.1版本中所做的优化 博客第1部分 博客第2部分 今天&#xff0c;我想简短介绍一下我们已经完成的最新开发&#xff0c;因为我们准备在本周末或下半年准备好构建和发布Camel 3.1。 从第2部分开始&#xff0c;我们设法在路由过程中将…

jvm jinfo 参数_jinfo:JVM运行时配置的命令行浏览

jvm jinfo 参数在最近的一些博客中&#xff08;特别是在对Java EE 7性能调优和优化以及WildFly性能调优的书中的评论中&#xff09;&#xff0c;我引用了自己过去在某些Oracle JDK命令行工具上的博客文章。 令我震惊的是&#xff0c;我从来没有专门解决过漂亮的jinfo工具&#…