为什么要编写单元测试–测试技巧8

我对最近在“您应该测试什么”上的博客有很多反应,有些人出于各种原因同意我的想法,另一些人则认为建议某些类可能不需要单元测试是非常危险的。 已经处理了什么测试,今天的博客涉及为什么要编写单元测试,而今天的示例代码是基于一个真实的故事:只有姓名,日期和事实已经改变。

一位客户最近请求紧急释放一些代码,以出于法律原因在其网站的相应页面上在屏幕上显示一条消息。

方案是,如果一条信息存在于数据库中,则应该在屏幕上显示一条信息–这是一个非常简单的方案,可以用几行简单的代码行覆盖。 但是,在急于编写代码的过程中,开发人员没有编写任何单元测试,并且代码中包含一个直到补丁到达UAT才发现的错误。 您可能会问到错误是什么,这是我们在职业生涯中某个时候都已经完成的事情:添加不需要的分号';'。 到一行的结尾。

我将使用我以前的“测试技术”博客中使用的AddressService场景来演示代码的重写特技双重版本,如下UML图所示:

在此演示中,功能已更改,但是逻辑和示例代码结构基本上保持不变。 在AddressService世界中,逻辑运行如下:

  1. 从数据库获取地址。
  2. 如果地址存在,则将其格式化并返回结果字符串。
  3. 如果地址不存在,则返回null。
  4. 如果格式化失败,请不要担心,并返回null。

重新编写的AddressService.findAddress(…)看起来像这样:

@Component
public class AddressService {private static final Logger logger = LoggerFactory.getLogger(AddressService.class);private AddressDao addressDao;public String findAddressText(int id) {logger.info("In Address Service with id: " + id);Address address = addressDao.findAddress(id);String formattedAddress = null;if (address != null);try {formattedAddress = address.format();} catch (AddressFormatException e) {// That's okay in this business case so ignore it}logger.info("Leaving Address Service with id: " + id);return formattedAddress;}@Autowired@Qualifier("addressDao")void setAddressDao(AddressDao addressDao) {this.addressDao = addressDao;}
}

您发现错误了吗? 当我查看代码时,我没有……为了以防万一,我在下面注释了一个屏幕截图:

演示一个琐碎的错误(任何人都可以犯的一个简单错误)的目的是强调编写一些单元测试的重要性,因为单元测试可以发现问题并节省大量的时间和费用。 当然,每个组织都不同,但是发布上面的代码会导致以下事件序列:

  • 该应用程序已部署到开发,测试和UAT。
  • 测试团队检查了修改后的屏幕是否可以正常工作并通过了更改。
  • 其他屏幕经过回归测试,发现不正确。 记录所有失败的屏幕。
  • 提出了紧急的错误报告。
  • 该报告通过各个管理级别。
  • 该报告已传递给我(我想念午餐),以调查可能的问题。
  • 该报告将发送给团队的其他三名成员进行调查(四双眼睛比一只更好)
  • 找到并修复了有问题的分号。
  • 该代码在dev中进行了重新测试,并签入到源代码管理中。
  • 该应用程序已构建并部署到开发,测试和UAT。
  • 测试团队检查修改后的屏幕是否可以正常工作并通过更改。
  • 其他屏幕经过回归测试并通过。
  • 紧急修复程序已通过。

上述一系列事件显然浪费了大量的工时,浪费了大量现金,不必要地提高了人们的压力水平,并破坏了我们在客户中的声誉: 所有这些都是编写单元测试的很好理由。

为了证明这一点,我编写了三个缺失的单元测试,只花了我额外的15分钟开发时间,与浪费的工时相比,这似乎是开发人员时间的一种很好的利用。

@RunWith(UnitilsJUnit4TestClassRunner.class)
public class WhyToTestAddressServiceTest {private AddressService instance;@Mockprivate AddressDao mockDao;@Mockprivate Address mockAddress;/*** @throws java.lang.Exception*/@Beforepublic void setUp() throws Exception {instance = new AddressService();instance.setAddressDao(mockDao);}/*** This test passes with the bug in the code* * Scenario: The Address object is found in the database and can return a* formatted address*/@Testpublic void testFindAddressText_Address_Found() throws AddressFormatException {final int id = 1;expect(mockDao.findAddress(id)).andReturn(mockAddress);expect(mockAddress.format()).andReturn("This is an address");replay();instance.findAddressText(id);verify();}/*** This test fails with the bug in the code* * Scenario: The Address Object is not found and the method returns null*/@Testpublic void testFindAddressText_Address_Not_Found() throws AddressFormatException {final int id = 1;expect(mockDao.findAddress(id)).andReturn(null);replay();instance.findAddressText(id);verify();}/*** This test passes with the bug in the code* * Scenario: The Address Object is found but the data is incomplete and so a* null is returned.*/@Testpublic void testFindAddressText_Address_Found_But_Cant_Format() throws AddressFormatException {final int id = 1;expect(mockDao.findAddress(id)).andReturn(mockAddress);expect(mockAddress.format()).andThrow(new AddressFormatException());replay();instance.findAddressText(id);verify();}
}

最后,冒着自鸣得意的风险,我不得不承认,尽管在这种情况下该错误不是我的,但在我学会编写单元测试之前,我过去曾大范围地发布了类似的错误……
可从GitHub上获得源代码:

git://github.com/roghughe/captaindebug.git

参考: 为什么要编写单元测试-来自JCG合作伙伴 Roger Hughes的测试技巧8 ,位于Captain Debug's Blog中 。

相关文章 :

  • 测试技巧–不编写测试
  • 端到端测试的滥用–测试技术2
  • 您应该对什么进行单元测试? –测试技术3
  • 常规单元测试和存根–测​​试技术4
  • 使用模拟的单元测试–测试技术5
  • 为旧版代码创建存根–测试技术6
  • 有关为旧版代码创建存根的更多信息–测试技术7
  • 一些定义–测试技术9

翻译自: https://www.javacodegeeks.com/2011/12/why-you-should-write-unit-tests-testing.html

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

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

相关文章

c++ 多重背包状态转移方程_动态规划入门——详解经典问题零一背包

本文始发于个人公众号:TechFlow,原创不易,求个关注今天是周三算法与数据结构专题的第12篇文章,动态规划之零一背包问题。在之前的文章当中,我们一起探讨了二分、贪心、排序和搜索算法,今天我们来看另一个非…

python定义一个圆_Python-矩形和圆形

原博文 2019-11-11 12:34 − Exercise 15.1. 定义一个叫做Circle 类,类的属性是圆心 (center) 和半径 (radius) , 其中,圆心 (center) 是一个 Point 类,而半径 (radius) 是一个数字。 实例化一个圆心 (center) 为 (150, 100) ,半…

STM32F1笔记(一)GPIO输出

GPIO:General Purpose Input Output (通用输入/输出)。 GPIO最经典应用:LED灯。 先看电路。声明:参考正点原子战舰开发板。 与LED串联的电阻称为限流电阻。 限流电阻计算公式:R(U-LED压降)/20ma。 U为LE…

dataframe转化为array_【Python专栏】12 种高效 Numpy 和 Pandas 函数为你加速分析

来源:机器之心编译:Jamin、杜伟、张倩我们都知道,Numpy 是 Python 环境下的扩展程序库,支持大量的维度数组和矩阵运算;Pandas 也是 Python 环境下的数据操作和分析软件包,以及强大的数据分析库。二者在日常…

具有GlassFish和一致性的高性能JPA –第1部分

您以前听说过连贯性吗? 大概是。 它是那些著名的内存网格解决方案之一,该解决方案承诺了超快的数据访问速度和对经常使用的数据的无限空间。 一些众所周知的竞争对手是Infinispan , Memcached和Terracotta Ehcache 。 它们都很棒,…

boost原理与sklearn源码_机器学习sklearn系列之决策树

一、 Sklearn库 Scikit learn 也简称 sklearn, 自2007年发布以来,scikit-learn已经成为Python重要的机器学习库了。支持包括分类、回归、降维和聚类四大机器学习算法。还包含了特征提取、数据处理和模型评估三大模块。sklearn是Scipy的扩展,建立在NumPy和…

STM32F1笔记(二)GPIO输入

STM32 GPIO输入的经典应用是按键。 先看电路。声明:参考正点原子战舰开发板。 在这里可以看到,KEY_UP按键是高电平有效的,即当按下该按键时,GPIO读到高电平。 KEY0/1/2是低电平有效的,即当按下该按键时,G…

STM32F1笔记(三)UART/USART

UART:Universal Asynchronous Receiver/Transmitter(通用异步收/发器) USART:Universal Synchronous/Asynchronous Receiver/Transmitter(通用同步/异步串行收/发器) 从命名即可看出USART就是UART的基础上…

python安装界面翻译_python环境搭建

如果想要运行python需要有解释器和编辑器。 什么是解释器 解释器我们可以把它理解成翻译官,它是将我们写的python代码翻译成计算机能够懂得机器语言。 然后计算机收到解释器的命令来干活,最终再将结果反馈在解释器中。 解释器推荐使用anaconda3 什么是an…

进阶篇-用户界面:4.Android中常用组件

1.下拉菜单 在Web开发中&#xff0c;HTML提供了下拉列表的实现&#xff0c;就是使用<select>元素实现一个下拉列表&#xff0c;在其中每个下拉列表项使用<option>表示即可。这是在Web开发中一个必不可少的交互性组件&#xff0c;而在Android中的对应实现就是Spinne…

http的“无连接”指的是_http协议无状态中的 quot;状态quot; 到底指的是什么?...

引子&#xff1a;最近在好好了解http&#xff0c;发现对介绍http的第一句话【http协议是无状态的&#xff0c;无连接的】就无法理解了&#xff1a;无状态的【状态】到底指的是什么&#xff1f;&#xff01;找了很多资料不仅没有发现有一针见血正面回答这个问题的&#xff0c;而…

个人日志-7.4

姓名 刘鑫 时间 2016.7.4 学习内容 完善需求分析报告。撰写数据库设计说明书。初步安排计划概要设计说明书。调整项目开发计划说明书。 所遇问题 无 解决方案 无 转载于:https://www.cnblogs.com/liuxin13070013/p/5641967.html

STM32F1笔记(五)外部中断EXTI

STM32的每个IO都可以作为外部中断的中断输入口。 STM32F103的中断控制器支持19个外部中断/事件请求。每个中断设有状态为&#xff0c;每个中断/事件都有独立的触发和屏蔽设置。 STM32F103的19个外部中断为&#xff1a; EXTI线0~15&#xff1a;对应外部IO口的输入中断。 EXT…

STM32F1笔记(六)独立看门狗IWDG

STM32F1内置了两个看门狗&#xff0c;独立看门狗IWDG和窗口看门狗WWDG&#xff0c;可以用来检测和解决由软件错误引起的故障。 IWDG最适合应用于那些需要看门狗作为一个在主程序之外&#xff0c;能够完全独立工作&#xff0c;并且对时间精度要求较低的场合。WWDG最适合那些要求…

在JSF 2中对定制验证器进行参数化

在JSF 2中编写自定义验证器并不复杂。 您实现Validator接口&#xff0c;添加FacesValidator批注&#xff0c;并在faces-config.xml中插入Validator声明&#xff0c; 仅此而已 。 一块蛋糕。 但是&#xff0c;让我们考虑以下情形&#xff1a; 您需要自定义日期验证器&#xff0c…

STM32F1笔记(七)WWDG窗口看门狗

窗口看门狗与独立看门狗最大的不同是中断&#xff0c;窗口看门狗拥有一个提前唤醒中断。也就是在快要产生复位的前一段时间&#xff08;T[6:0]0x40&#xff09;来提醒需要进行喂狗&#xff0c;否则将复位。因此当窗口看门狗的计数器值减到0x40的时候&#xff0c;产生中断&#…

groovy怎样从sql语句中截取表名_Mysql和SQL

基本概念1.数据库DataBase简称&#xff1a;DB2.什么数据库&#xff1f;——用于存储和管理数据的仓库。存储过程是一个预编译的SQL语句&#xff0c;优点是允许模块化的设计&#xff0c;就是说只需创建一次&#xff0c;以后在该程序中就可以调用多次。3.数据库的特点&#xff1a…

STM32F1笔记(八)时钟

STM32有五种时钟源 1、HSI。高速内部时钟&#xff0c;RC振荡器&#xff0c;频率为8MHz。 2、HSE。高速外部时钟&#xff0c;可接石英/陶瓷谐振器&#xff0c;或者借外部时钟源&#xff0c;频率范围为4MHz~16MHz。 3、PLL。锁相环倍频输出&#xff0c;其时钟输入源可选择为HS…

java常用工具类(一)

一、String工具类 package com.mkyong.common; import java.util.ArrayList; import java.util.List; /** * * String工具类. <br> * * author 宋立君 * date 2014年06月24日 */ public class StringUtil { private static final int INDEX_NO…

python可以下载百度文库_不用下载券也能下载百度文库资料,Python帮你轻松搞定...

大家可能平时都有在百度文库下载文档的经历&#xff0c;费尽心思好不容易在文库找了一份可以用的资料&#xff0c;一看需要用下载券下载&#xff0c;搞的人很烦。 有的人为了节省时间&#xff0c;就任性办理了个文库VIP&#xff0c;再也不用纠结怎么下文档了。如果你是一个百度…