hamcrest_重新设计Hamcrest
hamcrest
我在Hamcrest庫上做了幾篇文章 ,我確實很喜歡使用它,但是我希望對其進行一些更改。 我了解他們所做的大多數設計決策,但我認為其中一些確實不值得。
介紹Litecrest
我對庫所做的大多數更改都有助于減輕Hamcrest的負擔,因為我覺得有些事情不必要地減輕了負擔。 這就是為什么我將更改稱為Litecrest。 它不會是一個實際的庫; 這只是大聲思考。 我也希望您能從中學到一些有關設計庫的知識。
沒有說明
Description接口以及StringDescription和BaseDescription類實際上并不值得。 他們提供了列表轉換為字符串好看一些不錯的方法,但toString()在所有這些方法應該是足夠的。 如果不是這樣,可以將一些protected final方法放在BaseMatcher ,以方便地為列表構建字符串。 當然,這并沒有真正遵循SRP密切,所以你可以使用類似 Description ,以提供方便的方法。
說明,否則不是很有幫助。 它的存在性假設它專門用于提供從長遠來看可能不是String的輸出。 作為一個使用良好的庫,將其從String更改為與輸出無關的類型會破壞向后兼容,但這種更改不太可能需要。 應用YAGNI , Description類就在廁所下面。
無輸出參數
所述describeTo()和describeMismatch 不宜服用在Description或附加物體的任何其它類型的字符串,尤其是作為out參數(某物,以避免盡可能經常)。 既然這些方法沒有開始的返回類型,那么絕對沒有理由使用out參數。
仔細研究問題,您將發現根本沒有理由使用參數。 我了解到,他們可能一直在試圖迫使匹配器的創建者不使用String串聯,但事實并非如此。 如果匹配器的描述只是一個簡單的小字符串,則沒有理由他們不應該僅僅返回該字符串。 就個人而言,我將刪除Description參數,并為它們提供String或CharSequence的返回類型。 我考慮使用CharSequence因為那樣會給使用StringBuilder帶來更大的動力,但是簡單地返回String也不是什么大問題,因為他們可以在其上調用toString() 。 不過,我也可能會使用CharSequence ,因為我將在斷言邏輯中使用StringBuilder來將輸出放在一起,并且StringBuilder也可以接受CharSequence ,因此唯一的toString()必須在完成輸出時被調用。
類型安全
Matcher接口采用通用參數,該參數與matches()方法一起使用,但是所述方法采用Object而不是通用類型。 javadoc聲稱這是由于類型擦除引起的,但我不認為這是一個問題。 我沒有做任何挖掘來嘗試是否可以將其切換為通用類型,但是如果我發現您實際上可以使用通用類型,則可以。 這消除了對TypeSafeMatcher的需要,因為它也檢查null,因此可以用更簡單的NullCheckingMatcher代替,或者僅實現它,以便斷言在捕獲到NullPointerException將不匹配描述更改為“為null”。 通過執行所有這些操作,我們可以消除所有其他雙倍的基類,這些基類必須加倍以覆蓋類型安全匹配器和不那么重要的匹配器。 (例如: CustomMatcher和CustomTypeSafeMatcher , DiagnosingMatcher和TypeSafeDiagnosingMatcher ,以及我加倍的ChainableMatcher ,擺脫了兩個DiagnosingMatcher的影響;它們的設計很差,兩次調用matches() )
更改一些名字
我真的不喜歡describeTo()這個名字。 應該是describeExpected()或describeMatch() 。 我了解他們遵循JMock Constraints中SelfDescribing的命名約定,但是看到他們沒有費心完成其余方法簽名的復制,實際上并沒有任何SelfDescribing 。
CustomMatcher S的關系被稱為OneOffMatcher S或QuickMatcher秒。 Custom是一個令人誤解的名稱,聽起來您需要對其進行擴展才能創建自己的匹配器。
文檔中的更多示例
我不確定該庫中有幾類有用,因為它們的文檔未顯示其用法。 Condition就是其中之一。 從少量的文檔看來,這似乎是相對有用的,但是由于它沒有提供使用示例(并且它是一個具有內部接口和兩個內部類的相對復雜的文件),我不知道如何使用它。 它還沒有記錄其公共方法,因此我不確定它們是否需要大量研究。
FeatureMatcher已有不錯的文檔,但是同樣,沒有示例。
那些為圖書館編寫文檔的人在任何時候都牢記這一點; 如果不是很明顯(通常,即使不是很明顯),則應給出使用中的類的示例。
刪除無關的類
其中一些已經被直接或間接地解決了。 刪除Description及其所有子類。 刪除SelfDescribing ,因為它僅在Description仍然存在時才真正有用。 刪除所有TypeSafe版本的基本匹配器。 卸下Diagnosing匹配器。 我不確定是否應該刪除Condition因為我沒有太大用。 如果保留Condition ,那么最終在核心org.hamcrest包中有五個原始的十一個類,在api org.hamcrest包中有四個原始的兩個接口。
現在,讓我們深入研究org.hamcrest.internal包。 ArrayIterator沒什么用,因為您只能使用可以與foreach循環一起使用的數組。 NullSafety似乎模仿Arrays.toList()功能,但是用IsNull匹配器替換了null匹配器。 我看不到這有什么幫助,因此將其刪除。 ReflectiveTypeFinder可能最終會有用。 我只看到它在TypeSafeMatcher和FeatureMatcher ,盡管我不確定在FeatureMatcher使用了多少。 不過,我會保留。 最后兩個處理的是SelfDescribing ,我們已將其刪除,因此這兩個處理也是一樣。 這僅使ReflectiveTypeFinder脫離了以前的五個類。
我不打算討論所有其他匹配器。 在大多數情況下,已添加它們的用途。 由于刪除了這么多的基類,幾乎所有的類都可能必須進行更改。
Lambdas!
如果將新的功能范例也應用到hamcrest,則可以擴展匹配器概念的實用性。 我沒有想太多,但是對于一次性匹配器,您可以修改庫以包括一個新的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());} }這將使您可以編寫類似于以下內容的斷言:
assertThat("cats", "doesn't contain \"dogs\"", str -> !str.contains("dogs"));實際上,實際上我已經在ez-testing迷你庫中添加了LambdaAssert類,因此您可以將其與原始的hamcrest庫一起使用。
匹配器接口
實際上有一個Matcher接口是毫無意義的,因為hamcrest希望您擴展BaseMatcher而不是實現Matcher 。 如果您非常不想讓任何人實現,那么為什么要創建一個接口? 特別是因為BaseMatcher為我們所做的唯一事情就是為describeMismatch()創建一個默認實現describeMismatch()并“實現”放置在此處的不贊成使用的方法,告訴您使用BaseMatcher而不是Matcher )。
如果您真的不希望人們使用該界面,請擺脫它。 就我個人而言,由于無論如何我總是會重寫describeMismatch() ,因此我認為只實現接口就完全可以了,而不必讓JVM加載實際上為我提供任何東西的基類。
另外,由于我們現在有了Java 8,所以該接口可以只使用默認方法來實現默認實現。 我知道可以避免這種情況,因為較舊的Java版本將無法利用這一點。
所以,要么只是做BaseMatcher或沒事的Matcher正在實施。
奧托羅
我還想更改其他一些小事情,例如,迫使人們重寫describeMismatch()而不是提供默認值,但是我甚至不確定那個,因為默認值通常足夠有效。 無論如何,即使您有一個受歡迎的圖書館,也并不意味著它是完美的。 始終注意進行重構。
不幸的是,所有這些更改都不是向后兼容的,但有時是值得的。
翻譯自: https://www.javacodegeeks.com/2015/01/redesigning-hamcrest.html
hamcrest
總結
以上是生活随笔為你收集整理的hamcrest_重新设计Hamcrest的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 场院读音 场院到底念啥
- 下一篇: 咸吃萝卜淡操心是什么意思 咸吃萝卜淡操心
