存根类 测试代码 java_常规单元测试和存根–测​​试技术4

存根类 测试代码 java

我的上一个博客是有关测试代码的方法以及讨论您做什么和不必进行测试的方法的一系列博客中的第三篇。 它基于我使用一种非常常见的模式从数据库检索地址的简单方案:

…并且我提出了这样的想法,即任何不包含任何逻辑的类实际上都不需要单元测试。 在其中,我包括了我的数据访问对象DAO,它更喜欢对此类进行集成测试以确保其与数据库协同工作。

今天的博客涵盖编写常规或经典的单元测试,该测试使用存根对象强制实现测试主题隔离。 我们将要测试的代码再次是AddressService

@Component
public class AddressService {private static final Logger logger = LoggerFactory.getLogger(AddressService.class);private AddressDao addressDao;/*** Given an id, retrieve an address. Apply phony business rules.* * @param id*            The id of the address object.*/public Address findAddress(int id) {logger.info("In Address Service with id: " + id);Address address = addressDao.findAddress(id);address = businessMethod(address);logger.info("Leaving Address Service with id: " + id);return address;}private Address businessMethod(Address address) {logger.info("in business method");// Apply the Special Case Pattern (See MartinFowler.com)if (isNull(address)) {address = Address.INVALID_ADDRESS;}// Do some jiggery-pokery here....return address;}private boolean isNull(Object obj) {return obj == null;}@Autowired@Qualifier("addressDao")void setAddressDao(AddressDao addressDao) {this.addressDao = addressDao;}
}

迈克尔·费瑟(Michael Feather)的书《有效地使用旧版代码》指出,在以下情况下,测试不是单元测试:

  1. 它与数据库对话。
  2. 它通过网络进行通信。
  3. 它涉及文件系统。
  4. 您必须对环境做一些特殊的事情(例如编辑配置文件)才能运行它。

为了遵守这些规则,您需要将被测对象与系统的其余部分隔离开来,这就是存根对象的所在。存根对象是注入到您的对象中的对象,用于在测试情况下替换实际对象。 马丁·福勒(Martin Fowler)在他的论文《 莫克斯不是存根》中将存根定义为:

“存根提供对测试过程中进行的呼叫的固定答复,通常根本不响应为测试编程的内容之外的任何内容。 存根还可以记录有关呼叫的信息,例如电子邮件网关存根,它可以记住“已发送”的消息,或者仅记住“已发送”的消息数量。”

用一个单词来描述存根非常困难,我可以选择虚拟或伪造,但是有些替换对象称为假人或伪造,也由Martin Fowler描述:

  • 虚拟对象会传递,但从未实际使用过。 通常它们仅用于填充参数列表。
  • 伪对象实际上具有有效的实现,但是通常采取一些捷径,这使它们不适合生产(内存数据库就是一个很好的例子)。

但是,我看到过其他术语“伪造对象”的定义,例如Roy Osherove在《 The Art Of Unit Testing》一书中将伪造对象定义为:

  • 伪造品是一个通用术语,可用于描述存根或模拟对象……因为两者看起来都像真实对象。

…因此,我和其他许多人一样,倾向于将所有替换对象称为模拟或存根,因为两者之间存在差异,但稍后会更多。

在测试AddressService时 ,我们需要用存根数据访问对象替换实际的数据访问对象,在这种情况下,它看起来像这样:

public class StubAddressDao implements AddressDao {private final Address address;public StubAddressDao(Address address) {this.address = address;}/*** @see com.captaindebug.address.AddressDao#findAddress(int)*/@Overridepublic Address findAddress(int id) {return address;}
}

注意存根代码的简单性。 它应该易于阅读,可维护并且不包含任何逻辑,并且需要自己进行单元测试。 编写存根代码后,接下来进行单元测试:

public class ClassicAddressServiceWithStubTest {private AddressService instance;@Beforepublic void setUp() throws Exception {/* Create the object to test *//* Setup data that's used by ALL tests in this class */instance = new AddressService();}/*** Test method for* {@link com.captaindebug.address.AddressService#findAddress(int)}.*/@Testpublic void testFindAddressWithStub() {/* Setup the test data - stuff that's specific to this test */Address expectedAddress = new Address(1, "15 My Street", "My Town","POSTCODE", "My Country");instance.setAddressDao(new StubAddressDao(expectedAddress));/* Run the test */Address result = instance.findAddress(1);/* Assert the results */assertEquals(expectedAddress.getId(), result.getId());assertEquals(expectedAddress.getStreet(), result.getStreet());assertEquals(expectedAddress.getTown(), result.getTown());assertEquals(expectedAddress.getPostCode(), result.getPostCode());assertEquals(expectedAddress.getCountry(), result.getCountry());}@Afterpublic void tearDown() {/** Clear up to ensure all tests in the class are isolated from each* other.*/}
}

请注意,在编写单元测试时,我们的目标是清晰。 通常会犯一个错误,就是认为测试代码不如生产代码,从而导致测试代码更加混乱且难以辨认。 单元测试的艺术中的 Roy Osherove提出了这样的想法,即测试代码应比生产代码更具可读性。 明确的测试应遵循以下基本的线性步骤:

  1. 创建被测对象。 在上面的代码中,这是在setUp()方法中完成的,因为我对所有(一个)测试都使用了相同的被测对象。
  2. 设置测试。 这是在测试方法testFindAddressWithStub()中完成的,因为测试中使用的数据特定于该测试。
  3. 运行测试
  4. 撕毁测试。 这样可以确保测试相互隔离,并且可以按任何顺序运行。

使用简单的存根会产生将AddressService与外界隔离和快速运行测试的两个好处。

这种测试有多脆? 如果您的要求改变了,那么测试和存根就会改变–毕竟不是那么脆弱吗?

作为比较,我的下一个博客使用EasyMock重写了该测试。

参考:来自Captain Debug博客的 JCG合作伙伴 常规单元测试和存根-测试技术4

相关文章 :

  • 测试技巧–不编写测试
  • 端到端测试的滥用–测试技术2
  • 您应该对什么进行单元测试? –测试技术3
  • 使用模拟的单元测试–测试技术5
  • 为旧版代码创建存根-测试技术6
  • 有关为旧版代码创建存根的更多信息–测试技术7
  • 为什么要编写单元测试-测试技巧8
  • 一些定义–测试技术9
  • 使用FindBugs产生更少的错误代码
  • 在云中开发和测试

翻译自: https://www.javacodegeeks.com/2011/11/regular-unit-tests-and-stubs-testing.html

存根类 测试代码 java

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

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

相关文章

使用 Python 爬取网页数据

在需要过去一些网页上的信息的时候,使用 Python 写爬虫来爬取十分方便。 1. 使用 urllib.request 获取网页 urllib 是 Python 內建的 HTTP 库, 使用 urllib 可以只需要很简单的步骤就能高效采集数据; 配合 Beautiful 等 HTML 解析库, 可以编写出用于采集网络数据的…

多线程(初级篇)

相关概念进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。一个进程是一个独立的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一个包含了…

了解ADF生命周期中的ADF绑定

在本文中,我将重点介绍ADF绑定层,并探讨当最初从浏览器请求带有某些数据的ADF页面时,它如何工作。 Oracle ADF提供了自己的JSF生命周期扩展版。 实际上,ADF扩展了标准JSF生命周期实现类,并提供了ADF阶段侦听器&#x…

绕过 WAF:绕过一些 WAF 设备的 Burp 插件

我写了这个插件使用的技术博客文章在这里一会儿回来。如果存在特定标头,许多 WAF 设备可能会被诱骗相信请求来自自身,因此是可信的。绕过方法的基础知识可以在此处的 HP 博客文章中找到。 一段时间以来,我一直在 Burp 中实施匹配/替换规则&…

windows apache部署php,Windows下部署Apache+PHP+MySQL运行环境实战

首先是MySQL,(这边吐槽一下被Oracle收购的MySQL)一步一步往下,无需更多的配置然后安装Apache,也是一步一步往下安装PHP,(我偷懒我自豪, 在PHP下载页面找那个Installer的文件.......吐槽可能不是最新的版本 ~)下载页面安…

粉丝提问:有没有人会做彩虹表

彩虹表就是一个庞大的、针对各种可能的字母组合预先计算好的哈希值的集合,不一定是针对MD5算法的,各种算法的都有,有了它可以快速的破解各类密码。越是复杂的密码,需要的彩虹表就越大,现在主流的彩虹表都是100G以上。 …

fofa自动化爬虫脚本更新+详解

fofa自动化爬虫脚本更新详解 起因 最近要用到fofa爬虫,为什么要用爬虫不用api,问就是穷,想起来之前写过一个相关的脚本:Fofa-python-脚本,是很久以前写的了,之前写的时候有点问题,昨天重新修…

【APICloud系列|16】苹果开发者账号如何更改双重认证的手机号

按照一般的更改流程: 现在苹果账号安全系统升级,一般需要同意协议或者和本公司密切相关的人员才能操作。我这种借苹果手机操作的人除外。 那我用win7电脑如何操作呢? 登录苹果开发者账号, 进入如下管理账号地址:htt…

JS文件信息收集工具-LinkFinder

0x00 前言 我们在渗透测试的之前,信息收集是必要的步骤,而JS文件中往往会暴露出很多的信息,比如一些注释的中铭感信息,内网ip地址泄露等等,还会有一些绝对路径或者相对路径的url,而这些url中很有可能就存在…

extjs中Store和grid的刷新问题

问题1:Store.load() 和Store.setproxy()区别 问题2:修改后的Grid 更新: Store.reload() 问题3,store删除后刷新会出问题 Store移除一行:Store.removeAt(Number index) 从数据集中删除指定索引位置的记录     或者Store.reload…

【APICloud系列|28】苹果开发者账号应该如何续费?

本次更新时间:2020/7/13 登录苹果开发者账号,一般还有1个月到期官方会给你发邮件,不懂英文的可以使用谷歌翻译功能。 目前的后台提醒是这样的,我给你翻译一下 这个如果没有到期,使用Apple Developer这个应用程序进行充值缴费。 对应地址:https://developer.apple.com/i…

linux中第一个进程的形成,Linux进程管理

1.进程基本概述定义:进程是已经启动的可执行程序的运行中实例。/proc目录下以数字为名的目录,每一个目录代表一个进程,保留着进程的属性信息,每一个进程的PID是唯一的,就算进程退出了,其他进程也不会占用其…

XX(北京)科技股份公司为啥需要购置服务器?

其实老板只是要一个量化的标准,只是没人能讲明白,我简单陈述一下: 公司现在只有一台阿里的1核两G的1M带宽服务器40G,属于低配,买了3年的,打了三折花了2800元左右,为啥需要额外购置服务器呢? 目前服务器上有,一个后台管理系统,一个小程序,一个APP,一个网站,目前就…

[BZOJ 1588] [HNOI 2002] 营业额统计

1588: [HNOI2002]营业额统计 Time Limit: 5 SecMemory Limit: 162 MBDescription 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。 Tiger拿出了公司的账本,账本上记录了公司成立以…

Python----socket编程

socket 一、socket是什么? socket 通常也称为“套接字”,用于描述 IP 地址和端口,是一个通讯链的句柄。应用程序通常通过 “套接字”向网络发出请求或者应答网络请求。说白了,就是一种通讯机制。它类似于公司的电话客服部门&…

怎样编写测试类测试分支_测试技巧–不编写测试

怎样编写测试类测试分支对此没有太多疑问,测试代码的方式是一个有争议的问题。 不同的测试技术由于各种原因(包括企业文化,经验和总体心理观点)而受到不同开发人员的青睐。 例如,您可能更喜欢编写经典的单元测试&#…

怎么样才算高级java工程师

高级水平: 1.能对需求进行架构设计,选择框架以适应最合适的业务,作为某个项目的领导,带领团队完成项目。 2.有自己的开源项目,可以写出自己的组件,对开源的框架能够进行二次编写,java核心技术有…

Autorize插件的使用方法

在Proxy或者Repeater有Request请求包后,要ctrlA全选,然后再右键发送到Autorize插件中: 如果只是像这样空白的发送是不会发送过去的:

粉丝提问:求问大神您会查exif吗?

无需下载安装任何软件,直接上传图片即可查看EXIF。支持JPEG、TIFF、CR2、NEF、XMP等多种图片格式破解Canon、

linux和windows的分区区别,Linux分区与Windows分区的区别

打开开始-管理工具-计算机管理,如下图所示:在Windows系统中,计算机的分区是用磁盘0,磁盘1,磁盘2,磁盘3来表示多块硬盘的,比如磁盘0表示第一块硬盘,磁盘2表示第二块硬盘,以…