日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

双重for_测试双重图案

發(fā)布時(shí)間:2023/12/3 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 双重for_测试双重图案 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

雙重for

前段時(shí)間,我寫了一篇有關(guān)使用Test Double的后果的文章,但是與Test Double Patterns無關(guān),僅是一個(gè)簡單的清單。 今天,我想對其進(jìn)行更改,并解釋這些模式之間的差異。

正如我在提到的文章中寫道:

Test Double是允許我們控制被測單元之間依賴性的模式。 為了能夠在我們想要或/和/或驗(yàn)證是否發(fā)生想要的行為時(shí)提供想要的行為。
因此,現(xiàn)在當(dāng)您想起了基礎(chǔ)知識時(shí),我們可以轉(zhuǎn)到有趣的部分–讓我們看一下“測試雙重模式”。

虛擬對象

虛擬是TD(測試雙精度),當(dāng)我們想要傳遞對象以填充參數(shù)列表時(shí)使用。 從未實(shí)際使用過。 這就是為什么它不總是被視為TD之一的原因-它不提供任何行為。

假設(shè)我們有發(fā)送報(bào)告的Sender類。 由于某些要求,我們需要將其包裝到另一個(gè)類中以提供有效的接口。 我們的課看起來像這樣:

public class ReportProcessor implements Processor {private Sender sender;public ReportProcessor(Sender sender) {this.sender = sender;}@Overridepublic void process(Report report) {sender.send(report);} }

現(xiàn)在,我們的測試是什么樣的? 我們需要驗(yàn)證什么? 我們必須檢查報(bào)告是否傳遞給Sender實(shí)例的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);} }

如您所見,沒有與我們的虛擬對象進(jìn)行交互。 僅創(chuàng)建報(bào)告并將其作為參數(shù)傳遞。 沒有行為,只有存在。

假物件

Fake Object只是測試類所依賴的對象的一種更簡單,更輕量的實(shí)現(xiàn)。 它提供了預(yù)期的功能。

在決定時(shí)要記住的重要事項(xiàng)是使其盡可能簡單。 任何其他邏輯可能會對測試的脆弱性和準(zhǔn)確性產(chǎn)生重大影響。

假設(shè)我們有一個(gè)帶有create()方法的ReportService,它的職責(zé)是僅在尚未創(chuàng)建Report的情況下創(chuàng)建一個(gè)Report。 為簡單起見,我們可以假定標(biāo)題標(biāo)識一個(gè)對象–我們不能有兩個(gè)標(biāo)題相同的報(bào)表:

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,以確保每次調(diào)用它時(shí)結(jié)果都將完全符合我們的期望。

通常,我們不會在測試中檢查是否調(diào)用了Stub,因?yàn)槲覀儠ㄟ^其他斷言知道它。

在此示例中,我們將查看一個(gè)ReportFactory,該工廠將創(chuàng)建具有創(chuàng)建日期的報(bào)表。 為了可測試性,我們使用了依賴注入來注入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);} }

如您所見,我們僅對調(diào)用Stub的結(jié)果感興趣。

間諜對象

與Stub對象相反,當(dāng)我們對間諜方法的輸入感興趣時(shí),我們將使用Spies。 我們正在檢查它是否被調(diào)用。 我們可以檢查它被調(diào)用了多少次。

我們也可以將實(shí)際的應(yīng)用程序?qū)ο笥米鱏pies。 無需創(chuàng)建任何其他類。

讓我們從第一段回到ReportProcessor:

public class ReportProcessor implements Processor {// code@Overridepublic void process(Report report) {sender.send(report);} }

可能您已經(jīng)注意到我們在那里使用了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);} }

我們要檢查對象是否以正確的方式包裝,并將參數(shù)傳遞給其(包裝的對象)方法調(diào)用。 這就是為什么我們在這里使用Spy。

模擬對象

模擬對象通常被描述為Stub和Spy的組合。 我們指定期望接收的輸入,并在此基礎(chǔ)上返回正確的結(jié)果。

如果這是我們期望的,則調(diào)用模擬對象也可能導(dǎo)致拋出異常。

好的,讓我們再次看一下ReportService:

public class ReportService {//codepublic void create(Title title, Content content) {if (!reportRepository.existsWithTitle(title)) {Report report = new Report(title, content);reportRepository.add(report);}} }

現(xiàn)在,我們將使用模擬對象代替?zhèn)螌ο?#xff1a;

@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()方法。 如您所見,在第一個(gè)測試中,我們說如果調(diào)用帶有DUMMY_OBJECT參數(shù)的方法,它將返回true。 在第二個(gè)測試中,我們檢查相反的情況。

我們在兩個(gè)測試中的最后一個(gè)斷言(then()。should())是另一個(gè)TD模式。 你能認(rèn)出哪一個(gè)嗎?

最后一句話

這就是我今天要說的有關(guān)測試雙模式的全部內(nèi)容。 我鼓勵(lì)您有意使用它們,不要盲目遵循在可能的情況下添加@Mock注釋的習(xí)慣。

我還邀請您閱讀有關(guān)使用Test Double的后果的文章,以了解使用TD模式時(shí)可能遇到的問題以及如何識別和解決此類問題。

如果您想進(jìn)一步加深對這些模式的了解,那么會有一個(gè)很棒的頁面可以幫助您做到這一點(diǎn): xUnit Patterns:Test Double 。

祝您測試順利! 使它們可讀且有價(jià)值。

如果您對“測試雙模式”有任何想法或疑問,請?jiān)谠u論中分享。

翻譯自: https://www.javacodegeeks.com/2015/09/test-double-patterns.html

雙重for

總結(jié)

以上是生活随笔為你收集整理的双重for_测试双重图案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。