Mockito和Hamcrest的试驾制造商

过去,很多人问我是否测试吸气剂和吸气剂(属性,属性等)。 他们还问我是否测试我的建筑商。 在我看来,答案取决于情况。

当使用遗留代码时,我不会费心去测试数据结构,这意味着对象只带有getter和setter,映射,列表等。原因之一是我从不模拟它们。 在测试使用它们的类时,我照原样使用它们。 对于构建器,当它们仅由测试类使用时,我也不对它们进行单元测试,因为它们在许多其他测试中均被用作“帮助者”。 如果它们有错误,则测试将失败。 总而言之,如果这些数据结构和构建器已经存在,我不会为它们进行改装测试。

但是,现在让我们谈谈进行TDD并假设您需要一个带有getter和setter的新对象。 在这种情况下,是的,我将为吸气剂和吸气剂编写测试,因为我需要先编写测试来证明它们的存在。
为了拥有丰富的领域模型,我通常倾向于将业务逻辑与数据相关联,并拥有更丰富的领域模型。 让我们看下面的例子。

在现实生活中,我会一次编写测试,使它们通过并重构。 在这篇文章中,为清晰起见,我仅向您提供完整的课程。 首先让我们编写测试:

package org.craftedsw.testingbuilders;import static org.hamcrest.Matchers.is;import static org.junit.Assert.assertThat;import static org.mockito.Matchers.anyString;import static org.mockito.Mockito.verify;import static org.mockito.Mockito.when;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.Mock;import org.mockito.runners.MockitoJUnitRunner;@RunWith(MockitoJUnitRunner.class)public class TradeTest {private static final String INBOUND_XML_MESSAGE = '<message >';private static final boolean REPORTABILITY_RESULT = true;private Trade trade;@Mock private ReportabilityDecision reportabilityDecision;@Beforepublic void initialise() {trade = new Trade();when(reportabilityDecision.isReportable(anyString())).thenReturn(REPORTABILITY_RESULT);}@Test public voidshould_contain_the_inbound_xml_message() {trade.setInboundMessage(INBOUND_XML_MESSAGE);assertThat(trade.getInboundMessage(), is(INBOUND_XML_MESSAGE));}@Test public voidshould_tell_if_it_is_reportable() {trade.setInboundMessage(INBOUND_XML_MESSAGE);trade.setReportabilityDecision(reportabilityDecision);boolean reportable = trade.isReportable();verify(reportabilityDecision).isReportable(INBOUND_XML_MESSAGE);assertThat(reportable, is(REPORTABILITY_RESULT));}}

现在执行:

package org.craftedsw.testingbuilders;public class Trade {private String inboundMessage;private ReportabilityDecision reportabilityDecision;public String getInboundMessage() {return this.inboundMessage;}public void setInboundMessage(String inboundXmlMessage) {this.inboundMessage = inboundXmlMessage;}public boolean isReportable() {return reportabilityDecision.isReportable(inboundMessage);}public void setReportabilityDecision(ReportabilityDecision reportabilityDecision) {this.reportabilityDecision = reportabilityDecision;}}

这种情况很有趣,因为Trade对象具有一个名为inboundMessage的属性,具有相应的getter和setter,并且在其isReportable业务方法中还使用了一个协作者(reportabilityDecision,通过setter注入)。

我多次看到的“测试” setReportabilityDecision方法的常用方法是引入getReportabilityDecision方法,该方法返回reportabilityDecision(协作者)对象。

这绝对是错误的方法。 我们的目标应该是测试协作器的使用方式,这意味着是否使用正确的参数调用了协作器,以及是否使用了返回的任何内容(如果返回了任何内容)。 在这种情况下引入吸气剂是没有意义的,因为它不能保证在通过设置器注入了协作者之后,对象将按照我们的预期与协作者进行交互。

顺便说一句,当我们编写有关如何使用协作者的测试时,定义它们的接口是在将TDD用作设计工具而不仅仅是将其用作测试工具时。 我将在以后的博客文章中介绍。

好的,现在假设可以以不同的方式(即具有不同的可报告性决策)创建此贸易对象。 我们还希望使代码更具可读性,因此我们决定为Trade对象编写一个生成器。 在这种情况下,我们还假设我们希望生成器也用于生产和测试代码中。 在这种情况下,我们要测试驱动器。

这是我通常在开发人员测试驱动构建器实现时发现的一个示例。

package org.craftedsw.testingbuilders;import static org.craftedsw.testingbuilders.TradeBuilder.aTrade;import static org.hamcrest.Matchers.is;import static org.junit.Assert.assertThat;import static org.mockito.Mockito.verify;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.Mock;import org.mockito.runners.MockitoJUnitRunner;@RunWith(MockitoJUnitRunner.class)public class TradeBuilderTest {private static final String TRADE_XML_MESSAGE = '<message >';@Mockprivate ReportabilityDecision reportabilityDecision;@Test public voidshould_create_a_trade_with_inbound_message() {Trade trade = aTrade().withInboundMessage(TRADE_XML_MESSAGE).build();assertThat(trade.getInboundMessage(), is(TRADE_XML_MESSAGE));}@Test public voidshould_create_a_trade_with_a_reportability_decision() {Trade trade = aTrade().withInboundMessage(TRADE_XML_MESSAGE).withReportabilityDecision(reportabilityDecision).build();trade.isReportable();verify(reportabilityDecision).isReportable(TRADE_XML_MESSAGE);}}

现在让我们看看这些测试。 好消息是,这些测试是以开发人员想要阅读它们的方式编写的。 这也意味着他们正在“设计” TradeBuilder公共接口(公共方法)。 坏消息是他们如何对其进行测试。

如果仔细看,构建器的测试几乎与TradeTest类中的测试相同。
您可能会说没问题,因为构建器正在创建对象,并且测试应该相似。 唯一的不同是,在TradeTest中我们手动实例化对象,在TradeBuilderTest中我们使用构建器实例化对象,但是断言应该相同,对吗? 对于我来说,首先我们要重复。 其次,TradeBuilderTest没有显示出它的真实意图。 经过多次重构和探索不同的想法之后,在与团队中的一个人进行配对编程时,我们想到了这种方法:

package org.craftedsw.testingbuilders;import static org.mockito.BDDMockito.given;import static org.mockito.Mockito.verify;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.InjectMocks;import org.mockito.Mock;import org.mockito.Spy;import org.mockito.runners.MockitoJUnitRunner;@RunWith(MockitoJUnitRunner.class)public class TradeBuilderTest {private static final String TRADE_XML_MESSAGE = '<message >';@Mock private ReportabilityDecision reportabilityDecision;@Mock private Trade trade;@Spy @InjectMocks TradeBuilder tradeBuilder;@Test public voidshould_create_a_trade_with_all_specified_attributes() {given(tradeBuilder.createTrade()).willReturn(trade);tradeBuilder.withInboundMessage(TRADE_XML_MESSAGE).withReportabilityDecision(reportabilityDecision).build();verify(trade).setInboundMessage(TRADE_XML_MESSAGE);verify(trade).setReportabilityDecision(reportabilityDecision);}}

因此,现在,TradeBuilderTest表达了TradeBuilder的期望,即调用build方法时的副作用。 我们希望它创建交易并设置其属性。 TradeTest没有重复项。 它留给TradeTest来保证Trade对象的正确行为。
为了完整起见,这是最后的TradeBuider类:

package org.craftedsw.testingbuilders;public class TradeBuilder {private String inboundMessage;private ReportabilityDecision reportabilityDecision;public static TradeBuilder aTrade() {return new TradeBuilder();}public TradeBuilder withInboundMessage(String inboundMessage) {this.inboundMessage = inboundMessage;return this;}public TradeBuilder withReportabilityDecision(ReportabilityDecision reportabilityDecision) {this.reportabilityDecision = reportabilityDecision;return this;}public Trade build() {Trade trade = createTrade();trade.setInboundMessage(inboundMessage);trade.setReportabilityDecision(reportabilityDecision);return trade;}Trade createTrade() {return new Trade();}}

Mockito和Hamcrest的组合功能非常强大,使我们能够编写更好,更易读的测试。

参考:来自Crafts Software博客的JCG合作伙伴 Sandro Mancuso的Mockito和Hamcrest的测试驱动构建器 。


翻译自: https://www.javacodegeeks.com/2012/06/test-driving-builders-with-mockito-and.html

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

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

相关文章

php8更新,PHP 8 中新特性以及重大调整

PHP 8&#xff0c;PHP 的一个新的大版本&#xff0c;预计将于2020年12月3日发布&#xff0c;这意味着将不会有 PHP 7.5 版本。PHP8目前正处于非常活跃的开发阶段&#xff0c;所以在接下来的几个月里&#xff0c;情况可能会发生很大的变化。在这篇文章中&#xff0c;我会维持一个…

Javascript学习之函数(function)

http://www.cnblogs.com/royalroads/p/4418587.html 在JS中,Function(函数)类型实际上是对象;每个函数都是Function类型的实例&#xff0c;而且都与其他引用类型一样具有属性和方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针。 一 函数的声明方式 //1.函数声…

jquery弹出可关闭遮罩提示框

jquery CSS3遮罩弹出层动画效果&#xff0c;使用非常简单&#xff0c;就两个标签&#xff0c;里面自定义内容和样式&#xff0c;四种常见效果&#xff0c;懂的朋友还可以修改源代码修改成自己想要的效果效果展示 http://hovertree.com/texiao/jquery/85/代码如下&#xff1a; &…

用于Spring JPA2后端的REST CXF

在本演示中&#xff0c;我们将使用spring / jpa2后端生成一个REST / CXF应用程序。 该演示演示了分钟项目的轨迹REST-CXF 。 演示2中的模型保持不变。 浓缩保持不变。 但是轨道改变了 添加的是2层&#xff1a; 在JPA2之上具有弹簧集成的DAO层 具有JAX-RS批注的REST-CXF层…

php与服务器关系,php与web服务器关系

1.什么是cgi程序&#xff0c;cgi与fastcgi的区别CGI的中文名称是通用网关接口&#xff0c;是外部应用程序与web服务器之间的接口标准。CGI规范允许web服务器执行外部程序&#xff0c;并将它们的输出发送给web浏览器。而fastcgi则是一个常驻型的cgi&#xff0c;它可以一直执行着…

POJ 3468 A Simple Problem with Integers(线段树:区间更新)

http://poj.org/problem?id3468 题意&#xff1a; 给出一串数&#xff0c;每次在一个区间内增加c&#xff0c;查询[a,b]时输出a、b之间的总和。 思路&#xff1a; 总结一下懒惰标记的用法吧。 比如要对一个区间范围内的数都要加c&#xff0c;在找到这个区间之后&#xff0c;本…

php 新浪url,PHP URL函数详解

php url函数:parse_url()parse_url(PHP 3, PHP 4, PHP 5)parse_url -- 解析 URL&#xff0c;归来其构成局部解释array parse_url ( string url )本函数解析一个 URL 并归来一个关系数组&#xff0c;包括在 URL 中揭示的各种构成局部。本函数不是用来检讨给定 URL 的合法性的&am…

完整的WebApplication JSF EJB JPA JAAS –第1部分

这篇文章将是迄今为止我博客中最大的一篇文章&#xff01; 我们将看到完整的Web应用程序。 最新的技术将完成此工作&#xff08;直到今天&#xff09;&#xff0c;但是我将给出一些提示以显示如何使本文适用于较旧的技术。 在本文的结尾&#xff0c;您将找到要下载的源代码。 您…

Ajax和JavaScript的区别

javascript是一种在浏览器端执行的脚本语言&#xff0c;Ajax是一种创建交互式网页应用的开发技术 &#xff0c;它是利用了一系列相关的技术其中就包括javascript。Javascript是由网景公司开发的一种脚本语言&#xff0c;它和sun公司的java语言是没有任何关系的&#xff0c;它们…

大一

以后准备开始ACM的题目啦转载于:https://www.cnblogs.com/Aiden-/p/6562038.html

概念验证:玩! 构架

我们正在开始一个新项目&#xff0c;我们必须选择Web框架。 我们的默认选择是grails&#xff0c;因为团队已经拥有使用它的经验&#xff0c;但是我决定给Play&#xff01; 和Scala有机会。 玩&#xff01; 有很多很酷的东西&#xff0c;在我的评估中&#xff0c;它得到了很多加…

ldap统一用户认证php,针对LDAP服务器进行身份认证

Symfony提供了不同的方法来配合LDAP服务器使用。Security组件提供&#xff1a;ldap user provider&#xff0c;使用的是form_login_ldap authentication provider&#xff0c;用于针对一台使用了表单登录的LDAP服务器。同所有其他user provider一样&#xff0c;它可以同任何aut…

每天CookBook之JavaScript-039

IIFE的使用<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>039</title> </head> <body></body> <script type"text/javascript"> (function () {var i 0;fu…

Day-6:创建计算字段

字段&#xff1a;基本上与列的意思相同&#xff0c;经常互换使用&#xff0c;计算字段是运行时在SELECT语句内创建的&#xff0c;不实际存在于数据库表中。 拼接字段&#xff1a;将值联结到一起构成单个值 SQL中的SELECT语句中可以使用或||操作符拼接&#xff0c;但mysql中必须…

使用Hibernate加载或保存图像-MySQL

本教程将引导您逐步了解如何使用Hibernate从数据库&#xff08; MySQL &#xff09;保存和加载图像。 要求 对于此示例项目&#xff0c;我们将使用&#xff1a; Eclipse IDE &#xff08;您可以使用自己喜欢的IDE&#xff09;&#xff1b; MySQL &#xff08;您可以使用任何…

javaweb回顾第四篇Servlet异常处理

前言&#xff1a;很多网站为了给用户很好的用户体验性&#xff0c;都会提供比较友好的异常界面&#xff0c;现在我们在来回顾一下Servlet中如何进行异常处理的。 1&#xff1a;声明式异常处理 什么是声明式&#xff1a;就是在web.xml中声明对各种异常的处理方法。 是通过<er…

java开发cs教程,日常运维(一)

w命令&#xff1a;用于查看系统负载、显示已经登陆系统的用户列表&#xff0c;并显示用户正在执行的指令等信息第一行从左面开始显示的信息依次为&#xff1a;时间&#xff0c;系统运行时间&#xff0c;登录用户数&#xff0c;平均负载。第二行开始以及下面所有的行&#xff0c…

coursera 《现代操作系统》 -- 第五周 同步机制(1)

临界区块&#xff08;Critical section&#xff09;指的是一个访问共用资源&#xff08;例如&#xff1a;共用设备或是共用存储器&#xff09;的程序片段&#xff0c;而这些共用资源有无法同时被多个线程访问的特性。&#xff08;不是字面意思的一个区域&#xff0c;是程序片段…

java.lang.NoClassDefFoundError:如何解决–第2部分

本文是我们的NoClassDefFoundError故障排除系列的第2部分。 看一下第1部分 。 它将重点介绍最简单的NoClassDefFoundError问题类型。 本文对于Java初学者来说是理想的选择&#xff0c;我强烈建议您自己编译并运行示例Java程序。 今后将使用以下书写格式&#xff0c;并为您提供&…

Android开发技术周报 Issue#34

教程 Google Develop for Android 系列 前几天在G上看到Google Developers站点&#xff0c;有一个Android系列的文章&#xff0c;分享到个人微博&#xff0c;周末闲来没事就学写了下&#xff0c;把它们简单的翻译了下&#xff0c;没想到一发不可收拾&#xff0c;六篇文章全部都…