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
Mockito和Hamcrest的试驾制造商相关推荐
- mockito_Mockito和Hamcrest的试驾制造商
mockito 过去,很多人问我是否测试吸气剂和吸气剂(属性,属性等). 他们还问我是否测试我的建筑商. 在我看来,答案取决于情况. 当使用遗留代码时,我不会费心去测试数据结构,这意味着对象只带有ge ...
- maven mockito_如何:测试Maven项目(JUnit,Mockito,Hamcrest,AssertJ)中的依赖项
maven mockito 对于当今的大多数Java项目而言,JUnit本身还远远不够. 您还需要一个模拟库,也许还有其他东西. 在此迷你操作指南中,我介绍了可以在新的Java项目中开始的测试依赖项. ...
- 如何:在Maven项目(JUnit,Mockito,Hamcrest,AssertJ)中测试依赖项
对于当今的大多数Java项目,JUnit本身还远远不够. 您还需要一个模拟库,也许还有其他东西. 在此迷你操作指南中,我介绍了可以在新的Java项目中开始的测试依赖项. 一切都始于JUnit Mave ...
- 微服务架构下的测试之道
作者:袁慎建,崇尚简约,热爱编程 && 运动健身 && 知识分享,擅长敏捷开发实践,持续集成 && 持续交付,关注代码整洁 && TDD ...
- spring boot简介_Spring Boot简介
spring boot简介 在本教程中,我们将看一下Spring Boot,看看它与Spring框架有何不同. 我们还将讨论Spring Boot提供的各种功能. 什么是Spring Boot? 在开 ...
- 使用Spring Data MongoDB和Spring Boot进行数据聚合
MongoDB聚合框架旨在对文档进行分组并将其转换为聚合结果. 聚合查询包括定义将在管道中执行的几个阶段. 如果您对有关该框架的更深入的细节感兴趣,那么 mongodb docs是一个很好的起点. 这 ...
- java静态导入_Java中越来越多地接受静态导入吗?
java静态导入 曾经有一段时间,至少在礼貌的社会中,人们普遍认为使用" 不是 "一词是不可接受的. 确实,在那个时候(也许直到今天),很多人确实(也确实)不认为这不是一个真实的词 ...
- Java是否越来越接受静态导入?
曾经有一段时间,至少在礼貌的社会中,人们普遍认为使用" 不是 "一词是不可接受的. 确实,那时(也许直到今天),许多人确实(也确实)认为不是一个真实的词. 尽管这个词并没有 引起争 ...
- 【Android进阶】20、音频播放:SoundPool 类、单元测试:Espresso框架
文章目录 20.1 创建 SoundPool 20.2 访问 assets 20.3 加载音频文件 20.4 播放音频 20.5 单元测试 20.6 创建测试类 20.7 配置测试类 20.8 编写测 ...
最新文章
- React接入Sentry.js
- 【Python】垃圾分类,调用阿里云API
- 服务器运行环境怎么搭建,服务器运行环境怎么快速搭建?
- HDU 5938 Four Operations 【字符串处理,枚举,把数字字符串变为数值】
- LI标签在Ul中居中显示
- 剑指offer(15)反转链表
- leetcode349. 两个数组的交集(思路+详解)
- P2568-GCD【欧拉函数,欧拉筛】
- 工作流实战_07_flowable 流程定义查看流程图和xml
- Java双端队列Deque及其应用
- 注入器 过检测_福特全顺V348检测车报价
- 练习:----计算阶乘按钮
- 练习|Django-单表
- 2020张宇1000题【好题收集】【第七章:三重积分、曲线曲面积分】
- mysql 批量 插入或更新
- Jquery中fadein() fadeout()方法的使用
- 盘点“大宗商品电子交易模式”的8种交易流程
- 跨模态检索 | Visual Representation Learning
- Qwerty Learner:为键盘工作者设计的单词记忆与英语肌肉记忆锻炼网页
- ehvierwer登录与不登录_微信号提示“系统检测有被盗风险”登录不上去该如何解决?...