hamcrest_重新设计Hamcrest
hamcrest
我在Hamcrest庫上做了幾篇文章 ,我確實(shí)很喜歡使用它,但是我希望對(duì)其進(jìn)行一些更改。 我了解他們所做的大多數(shù)設(shè)計(jì)決策,但我認(rèn)為其中一些確實(shí)不值得。
介紹Litecrest
我對(duì)庫所做的大多數(shù)更改都有助于減輕Hamcrest的負(fù)擔(dān),因?yàn)槲矣X得有些事情不必要地減輕了負(fù)擔(dān)。 這就是為什么我將更改稱為Litecrest。 它不會(huì)是一個(gè)實(shí)際的庫; 這只是大聲思考。 我也希望您能從中學(xué)到一些有關(guān)設(shè)計(jì)庫的知識(shí)。
沒有說明
Description接口以及StringDescription和BaseDescription類實(shí)際上并不值得。 他們提供了列表轉(zhuǎn)換為字符串好看一些不錯(cuò)的方法,但toString()在所有這些方法應(yīng)該是足夠的。 如果不是這樣,可以將一些protected final方法放在BaseMatcher ,以方便地為列表構(gòu)建字符串。 當(dāng)然,這并沒有真正遵循SRP密切,所以你可以使用類似 Description ,以提供方便的方法。
說明,否則不是很有幫助。 它的存在性假設(shè)它專門用于提供從長遠(yuǎn)來看可能不是String的輸出。 作為一個(gè)使用良好的庫,將其從String更改為與輸出無關(guān)的類型會(huì)破壞向后兼容,但這種更改不太可能需要。 應(yīng)用YAGNI , Description類就在廁所下面。
無輸出參數(shù)
所述describeTo()和describeMismatch 不宜服用在Description或附加物體的任何其它類型的字符串,尤其是作為out參數(shù)(某物,以避免盡可能經(jīng)常)。 既然這些方法沒有開始的返回類型,那么絕對(duì)沒有理由使用out參數(shù)。
仔細(xì)研究問題,您將發(fā)現(xiàn)根本沒有理由使用參數(shù)。 我了解到,他們可能一直在試圖迫使匹配器的創(chuàng)建者不使用String串聯(lián),但事實(shí)并非如此。 如果匹配器的描述只是一個(gè)簡單的小字符串,則沒有理由他們不應(yīng)該僅僅返回該字符串。 就個(gè)人而言,我將刪除Description參數(shù),并為它們提供String或CharSequence的返回類型。 我考慮使用CharSequence因?yàn)槟菢訒?huì)給使用StringBuilder帶來更大的動(dòng)力,但是簡單地返回String也不是什么大問題,因?yàn)樗麄兛梢栽谄渖险{(diào)用toString() 。 不過,我也可能會(huì)使用CharSequence ,因?yàn)槲覍⒃跀嘌赃壿嬛惺褂肧tringBuilder來將輸出放在一起,并且StringBuilder也可以接受CharSequence ,因此唯一的toString()必須在完成輸出時(shí)被調(diào)用。
類型安全
Matcher接口采用通用參數(shù),該參數(shù)與matches()方法一起使用,但是所述方法采用Object而不是通用類型。 javadoc聲稱這是由于類型擦除引起的,但我不認(rèn)為這是一個(gè)問題。 我沒有做任何挖掘來嘗試是否可以將其切換為通用類型,但是如果我發(fā)現(xiàn)您實(shí)際上可以使用通用類型,則可以。 這消除了對(duì)TypeSafeMatcher的需要,因?yàn)樗矙z查null,因此可以用更簡單的NullCheckingMatcher代替,或者僅實(shí)現(xiàn)它,以便斷言在捕獲到NullPointerException將不匹配描述更改為“為null”。 通過執(zhí)行所有這些操作,我們可以消除所有其他雙倍的基類,這些基類必須加倍以覆蓋類型安全匹配器和不那么重要的匹配器。 (例如: CustomMatcher和CustomTypeSafeMatcher , DiagnosingMatcher和TypeSafeDiagnosingMatcher ,以及我加倍的ChainableMatcher ,擺脫了兩個(gè)DiagnosingMatcher的影響;它們的設(shè)計(jì)很差,兩次調(diào)用matches() )
更改一些名字
我真的不喜歡describeTo()這個(gè)名字。 應(yīng)該是describeExpected()或describeMatch() 。 我了解他們遵循JMock Constraints中SelfDescribing的命名約定,但是看到他們沒有費(fèi)心完成其余方法簽名的復(fù)制,實(shí)際上并沒有任何SelfDescribing 。
CustomMatcher S的關(guān)系被稱為OneOffMatcher S或QuickMatcher秒。 Custom是一個(gè)令人誤解的名稱,聽起來您需要對(duì)其進(jìn)行擴(kuò)展才能創(chuàng)建自己的匹配器。
文檔中的更多示例
我不確定該庫中有幾類有用,因?yàn)樗鼈兊奈臋n未顯示其用法。 Condition就是其中之一。 從少量的文檔看來,這似乎是相對(duì)有用的,但是由于它沒有提供使用示例(并且它是一個(gè)具有內(nèi)部接口和兩個(gè)內(nèi)部類的相對(duì)復(fù)雜的文件),我不知道如何使用它。 它還沒有記錄其公共方法,因此我不確定它們是否需要大量研究。
FeatureMatcher已有不錯(cuò)的文檔,但是同樣,沒有示例。
那些為圖書館編寫文檔的人在任何時(shí)候都牢記這一點(diǎn); 如果不是很明顯(通常,即使不是很明顯),則應(yīng)給出使用中的類的示例。
刪除無關(guān)的類
其中一些已經(jīng)被直接或間接地解決了。 刪除Description及其所有子類。 刪除SelfDescribing ,因?yàn)樗鼉H在Description仍然存在時(shí)才真正有用。 刪除所有TypeSafe版本的基本匹配器。 卸下Diagnosing匹配器。 我不確定是否應(yīng)該刪除Condition因?yàn)槲覜]有太大用。 如果保留Condition ,那么最終在核心org.hamcrest包中有五個(gè)原始的十一個(gè)類,在api org.hamcrest包中有四個(gè)原始的兩個(gè)接口。
現(xiàn)在,讓我們深入研究org.hamcrest.internal包。 ArrayIterator沒什么用,因?yàn)槟荒苁褂每梢耘cforeach循環(huán)一起使用的數(shù)組。 NullSafety似乎模仿Arrays.toList()功能,但是用IsNull匹配器替換了null匹配器。 我看不到這有什么幫助,因此將其刪除。 ReflectiveTypeFinder可能最終會(huì)有用。 我只看到它在TypeSafeMatcher和FeatureMatcher ,盡管我不確定在FeatureMatcher使用了多少。 不過,我會(huì)保留。 最后兩個(gè)處理的是SelfDescribing ,我們已將其刪除,因此這兩個(gè)處理也是一樣。 這僅使ReflectiveTypeFinder脫離了以前的五個(gè)類。
我不打算討論所有其他匹配器。 在大多數(shù)情況下,已添加它們的用途。 由于刪除了這么多的基類,幾乎所有的類都可能必須進(jìn)行更改。
Lambdas!
如果將新的功能范例也應(yīng)用到hamcrest,則可以擴(kuò)展匹配器概念的實(shí)用性。 我沒有想太多,但是對(duì)于一次性匹配器,您可以修改庫以包括一個(gè)新的assertThat()方法,如下所示:
public static void assertThat(T item, String description, Predicate matcher) {if(!matcher.test(item)) {StringBuilder output = new StringBuilder();output.append("Expected: ").append(description).append("\n but: was").append(item.toString());throw new AssertionError(output.toString());} }這將使您可以編寫類似于以下內(nèi)容的斷言:
assertThat("cats", "doesn't contain \"dogs\"", str -> !str.contains("dogs"));實(shí)際上,實(shí)際上我已經(jīng)在ez-testing迷你庫中添加了LambdaAssert類,因此您可以將其與原始的hamcrest庫一起使用。
匹配器接口
實(shí)際上有一個(gè)Matcher接口是毫無意義的,因?yàn)閔amcrest希望您擴(kuò)展BaseMatcher而不是實(shí)現(xiàn)Matcher 。 如果您非常不想讓任何人實(shí)現(xiàn),那么為什么要?jiǎng)?chuàng)建一個(gè)接口? 特別是因?yàn)锽aseMatcher為我們所做的唯一事情就是為describeMismatch()創(chuàng)建一個(gè)默認(rèn)實(shí)現(xiàn)describeMismatch()并“實(shí)現(xiàn)”放置在此處的不贊成使用的方法,告訴您使用BaseMatcher而不是Matcher )。
如果您真的不希望人們使用該界面,請(qǐng)擺脫它。 就我個(gè)人而言,由于無論如何我總是會(huì)重寫describeMismatch() ,因此我認(rèn)為只實(shí)現(xiàn)接口就完全可以了,而不必讓JVM加載實(shí)際上為我提供任何東西的基類。
另外,由于我們現(xiàn)在有了Java 8,所以該接口可以只使用默認(rèn)方法來實(shí)現(xiàn)默認(rèn)實(shí)現(xiàn)。 我知道可以避免這種情況,因?yàn)檩^舊的Java版本將無法利用這一點(diǎn)。
所以,要么只是做BaseMatcher或沒事的Matcher正在實(shí)施。
奧托羅
我還想更改其他一些小事情,例如,迫使人們重寫describeMismatch()而不是提供默認(rèn)值,但是我甚至不確定那個(gè),因?yàn)槟J(rèn)值通常足夠有效。 無論如何,即使您有一個(gè)受歡迎的圖書館,也并不意味著它是完美的。 始終注意進(jìn)行重構(gòu)。
不幸的是,所有這些更改都不是向后兼容的,但有時(shí)是值得的。
翻譯自: https://www.javacodegeeks.com/2015/01/redesigning-hamcrest.html
hamcrest
總結(jié)
以上是生活随笔為你收集整理的hamcrest_重新设计Hamcrest的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 场院读音 场院到底念啥
- 下一篇: jpa 实体图查询_JPA实体图