双重for_测试双重图案
双重for
前段时间,我写了一篇有关使用Test Double的后果的文章,但是与Test Double Patterns无关,仅是一个简单的清单。 今天,我想对其进行更改,并解释这些模式之间的差异。
正如我在提到的文章中写道:
Test Double是允许我们控制被测单元之间依赖性的模式。 为了能够在我们想要或/和/或验证是否发生想要的行为时提供想要的行为。
因此,现在当您想起了基础知识时,我们可以转到有趣的部分–让我们看一下“测试双重模式”。
虚拟对象
虚拟是TD(测试双精度),当我们想要传递对象以填充参数列表时使用。 从未实际使用过。 这就是为什么它不总是被视为TD之一的原因-它不提供任何行为。
假设我们有发送报告的Sender类。 由于某些要求,我们需要将其包装到另一个类中以提供有效的接口。 我们的课看起来像这样:
public class ReportProcessor implements Processor {private Sender sender;public ReportProcessor(Sender sender) {this.sender = sender;}@Overridepublic void process(Report report) {sender.send(report);}
}
现在,我们的测试是什么样的? 我们需要验证什么? 我们必须检查报告是否传递给Sender实例的send()方法。 可以按照以下步骤完成:
public class DummyTest {@Testpublic void shouldSentReportWhileProcessing() {Sender sender = aMessageSender();ReportProcessor reportProcessor = aReportProcessor(sender);Report dummyReport = new Report();reportProcessor.process(dummyReport);then(sender).should().send(dummyReport);}private ReportProcessor aReportProcessor(Sender sender) {return new ReportProcessor(sender);}private Sender aMessageSender() {return spy(Sender.class);}
}
如您所见,没有与我们的虚拟对象进行交互。 仅创建报告并将其作为参数传递。 没有行为,只有存在。
假物件
Fake Object只是测试类所依赖的对象的一种更简单,更轻量的实现。 它提供了预期的功能。
在决定时要记住的重要事项是使其尽可能简单。 任何其他逻辑可能会对测试的脆弱性和准确性产生重大影响。
假设我们有一个带有create()方法的ReportService,它的职责是仅在尚未创建Report的情况下创建一个Report。 为简单起见,我们可以假定标题标识一个对象–我们不能有两个标题相同的报表:
public class ReportService {private ReportRepository reportRepository;public ReportService(ReportRepository reportRepository) {this.reportRepository = reportRepository;}public void create(Title title, Content content) {if (!reportRepository.existsWithTitle(title)) {Report report = new Report(title, content);reportRepository.add(report);}}
}
我们可以通过多种方式测试此代码,但是我们将决定使用Fake Object:
class FakeReportRepository implements ReportRepository {private Map<Title, Report> reports = new HashMap<>();@Overridepublic void add(Report report) {reports.put(report.title(), report);}@Overridepublic boolean existsWithTitle(Title title) {return reports.containsKey(title);}@Overridepublic int countAll() {return reports.size();}@Overridepublic Report findByTitle(Title title) {return reports.get(title);}
}
我们的测试将如下所示:
public class FakeTest {@Testpublic void shouldNotCreateTheSameReportTwice() {FakeReportRepository reportRepository = new FakeReportRepository();ReportService reportService = aReportService(reportRepository);reportService.create(DUMMY_TITLE, DUMMY_CONTENT);reportService.create(DUMMY_TITLE, DUMMY_CONTENT);Report createdReport = reportRepository.findByTitle(DUMMY_TITLE);assertThat(createdReport.title()).isSameAs(DUMMY_TITLE);assertThat(createdReport.content()).isSameAs(DUMMY_CONTENT);assertThat(reportRepository.countAll()).isEqualTo(1);}private ReportService aReportService(ReportRepository reportRepository) {return new ReportService(reportRepository);}
}
存根对象
我们在对方法输出感兴趣的情况下使用Stub Object,以确保每次调用它时结果都将完全符合我们的期望。
通常,我们不会在测试中检查是否调用了Stub,因为我们会通过其他断言知道它。
在此示例中,我们将查看一个ReportFactory,该工厂将创建具有创建日期的报表。 为了可测试性,我们使用了依赖注入来注入DateProvider:
public class ReportFactory {private DateProvider dateProvider;public ReportFactory(DateProvider dateProvider) {this.dateProvider = dateProvider;}public Report crete(Title title, Content content) {return new Report(title, content, dateProvider.date());}
}
它允许我们在测试中使用Stub:
public class StubTest {@Testpublic void shouldCreateReportWithCreationDate() {Date dummyTodayDate = new Date();DateProvider dateProvider = mock(DateProvider.class);stub(dateProvider.date()).toReturn(dummyTodayDate);ReportFactory reportFactory = new ReportFactory(dateProvider);Report report = reportFactory.crete(DUMMY_TITLE, DUMMY_CONTENT);assertThat(report.creationDate()).isSameAs(dummyTodayDate);}
}
如您所见,我们仅对调用Stub的结果感兴趣。
间谍对象
与Stub对象相反,当我们对间谍方法的输入感兴趣时,我们将使用Spies。 我们正在检查它是否被调用。 我们可以检查它被调用了多少次。
我们也可以将实际的应用程序对象用作Spies。 无需创建任何其他类。
让我们从第一段回到ReportProcessor:
public class ReportProcessor implements Processor {// code@Overridepublic void process(Report report) {sender.send(report);}
}
可能您已经注意到我们在那里使用了Spy,但让我们再次看一下测试:
public class SpyTest {@Testpublic void shouldSentReportWhileProcessing() {Sender sender = spy(Sender.class);ReportProcessor reportProcessor = aReportProcessor(sender);reportProcessor.process(DUMMY_REPORT);then(sender).should().send(DUMMY_REPORT);}private ReportProcessor aReportProcessor(Sender sender) {return new ReportProcessor(sender);}
}
我们要检查对象是否以正确的方式包装,并将参数传递给其(包装的对象)方法调用。 这就是为什么我们在这里使用Spy。
模拟对象
模拟对象通常被描述为Stub和Spy的组合。 我们指定期望接收的输入,并在此基础上返回正确的结果。
如果这是我们期望的,则调用模拟对象也可能导致抛出异常。
好的,让我们再次看一下ReportService:
public class ReportService {//codepublic void create(Title title, Content content) {if (!reportRepository.existsWithTitle(title)) {Report report = new Report(title, content);reportRepository.add(report);}}
}
现在,我们将使用模拟对象代替伪对象:
@RunWith(MockitoJUnitRunner.class)
public class MockTest {@Mock private ReportRepository reportRepository;@InjectMocks private ReportService reportService;@Testpublic void shouldCreateReportIfDoesNotExist() {given(reportRepository.existsWithTitle(DUMMY_TITLE)).willReturn(false);reportService.create(DUMMY_TITLE, DUMMY_CONTENT);then(reportRepository).should().add(anyReport());}@Testpublic void shouldNotCreateReportIfDoesNotExist() {given(reportRepository.existsWithTitle(DUMMY_TITLE)).willReturn(true);reportService.create(DUMMY_TITLE, DUMMY_CONTENT);then(reportRepository).should(never()).add(anyReport());}private Report anyReport() {return any(Report.class);}
}
为了澄清一切,我们的模拟对象是ReportRepository.existsWithTitle()方法。 如您所见,在第一个测试中,我们说如果调用带有DUMMY_OBJECT参数的方法,它将返回true。 在第二个测试中,我们检查相反的情况。
我们在两个测试中的最后一个断言(then()。should())是另一个TD模式。 你能认出哪一个吗?
最后一句话
这就是我今天要说的有关测试双模式的全部内容。 我鼓励您有意使用它们,不要盲目遵循在可能的情况下添加@Mock注释的习惯。
我还邀请您阅读有关使用Test Double的后果的文章,以了解使用TD模式时可能遇到的问题以及如何识别和解决此类问题。
如果您想进一步加深对这些模式的了解,那么会有一个很棒的页面可以帮助您做到这一点: xUnit Patterns:Test Double 。
祝您测试顺利! 使它们可读且有价值。
如果您对“测试双模式”有任何想法或疑问,请在评论中分享。
翻译自: https://www.javacodegeeks.com/2015/09/test-double-patterns.html
双重for
双重for_测试双重图案相关推荐
- 银行的双重生物识别实验,是双重麻烦还是双重安全?
这两个生物识别技术分辨是人脸识别.指纹识别,在实验中,都是通过移动设备实现的,而两家银行分别是匈牙利的OTP银行和西班牙的Liberbank.理论上,这两种生物识别技术叠加起来,肯定是最安全的.但这项 ...
- python 双重差分_双重差分的理论与实践
1. 理论 1.1 标准表述(定义) 双重差分模型(difference-in-differences)主要被用于社会学中的政策效果评估.其原理是基于一个反事实的框架来评估政策发生和不发生这两种情况下 ...
- python用双重循环输出菱形图案_使用循环创建菱形图案
以下几点怎么样:side = int(input("Please input side length of diamond: ")) for x in list(range(sid ...
- python 双重差分_双重差分法(DID)介绍
双重差分法,英文名Differences-in-Differences,别名"倍差法",小名"差中差".作为政策效应评估方法中的一大利器,双重差分法受到越来越多 ...
- 测试的双重目的性及理性质量观
我在上测试培训时,最爱问的一个开场问题就是"请大家说说测试的目的是什么?",这时你会听到五花八门的答案,其中最有代表性的答案有两个:一个是"测试的目的是找bug" ...
- 1.1.4 分支, if, if else, if elseif else, switch,循环,for,break,continue,双重for,while, do while
&&&&&总结&&&&& 1, 分支结构 if分支结构, if else分支结构, if elseif else分支结构 ...
- PS教程:Photoshop 中实现双重曝光效果的 5 个专业技巧和 7 个步骤
在知识兔本教程中,我将向您展示如何在 Photoshop 中创建双重曝光效果.双重曝光效果可以通过组合多个库存图像.尝试混合模式和使用调整图层来实现.我们还将学习如何在多个图像之间进行过渡并使用图层蒙 ...
- Java中的双重检查锁(double checked locking)
起因 在实现单例模式时,如果未考虑多线程的情况,很容易写出下面的代码(也不能说是错误的): public class Singleton {private static Singleton uniqu ...
- java 双重检查锁 有序_Java中的双重检查锁(double checked locking)
1 public classSingleton {2 private staticSingleton uniqueSingleton;3 4 privateSingleton() {5 }6 7 pu ...
最新文章
- python中异常的姓名
- java开源库生成折线图_Android HelloChart开源库图表之折线图的实例代码
- 禁止 VMware Fusion 自动调整 Windows 分辨率
- 选redis还是memcache,源码怎么说?
- 深度学习模型在训练集上很好而在测试集表现得不好而拟合次数并不多_机器学习中的过拟合,欠拟合和偏倚方差折衷...
- springboot + mybatis + 多数据源
- android fresco 存储,Android使用Fresco之下载图片(包括GIF图)
- 泰安本地话听不懂,为何后来能勉强听懂?
- CMMI中的过程改进
- python实现基于selenium的天猫淘宝秒杀,支持定金商品,自动付款
- win10易升_史上最稳定的win10版本,四大更新内容强势来袭,你敢升级吗?
- 台达变频器s1参数设置_台达变频器的参数设定步骤
- pyinstaller使用错误 SyntaxError: Non-UTF-8 code starting with '\xb4' in file C:......
- mongoDB 注册成开启自启动项
- 我的世界服务器ess配置文件,《我的世界》ess指令大全及用法详解
- ICCV, ECCV, CVPR,IEEE的关系
- 手把手教大家在mac上用VMWare虚拟机装Ubuntu
- Html5 Egret游戏开发 成语大挑战(七)游戏逻辑和数据处理
- java的碳刀_骑行圈的十万个为什么—碳刀简述1
- .htaccess技巧: URL重写(Rewrite)与重定向(Redirect)
热门文章
- P2387-[NOI2014]魔法森林【LCT】
- P1169-[ZJOI2007]棋盘制作【贪心】
- C++STL(set……)
- codeforces1451 E. Bitwise Queries(位运算妙用)
- 【KMP】重复子串(ybtoj KMP-2)
- 【二分】【暴力】蛋糕(gmoj 3918)
- [POI2015] Pustynia(差分约数,线段树优化建图,拓扑)
- 三元环计数四元环计数
- 25、jdbc操作数据库(2)
- mybatis3中@SelectProvider的使用技巧