道格拉斯·坎貝爾,首席工程師
I/E/A = 輸入/預期/實際
如果可以為下面的函數集提供實現,
// defines how to go from file to an instance of IN
abstract IN loadInput(File input);
// defines how to go from file to OUT instances
// throw FNF whenever there’s no expected file.
abstract OUT loadOutput(File expected) throws FileNotFoundException;
// invoked upon missing expected file or if actual != expected
abstract void storeResult(OUT result, File resultFile);
可以做很多工作來排除測試文檔轉換的苦差事,並維護一組可靠的測試。
簡而言之,它變成了將測試用例寫成檔而不是函數。
我非常喜歡這種方法來測試文檔轉換,而不是使用測試代碼。 首先,一個小背景。
背景
我多年來編寫的很多代碼的核心都將一種格式的文檔更改為另一種格式。通過文檔,我談論的是任何種類的json,xml,avro,標籤分隔,yaml,什麼 - 任何東西和一切到任何東西和一切,然後又回來了。
當被要求編寫類似內容時,許多開發人員的眼睛只是在編寫一些瑣碎的東西時,就像將一個字段映射到另一個字段、將其佔據上部、將其與從某些外部數據源讀取的另一個值融合在一起,然後放入另一個表示形式的恐怖。
這種新的表示形式可能與初始文檔沒有什麼相似之處。這就是野獸的本質。
簡而言之,推動數據轉換的要求是完全武斷的!
我想這就是一些開發人員討厭這些東西的原因。他們採取捷徑,並拋出的東西到測試代碼,看起來像這樣...
//CHECKSTYLE:OFF
private static final String CLICK = "a horrendously ugly line of input from an access log";
//CHECKSTYLE:ON
當是時候測試一個"印象",猜測會發生什麼。Ugh = 將輸入內聯為字串變數。抑制檢查方式後,Spidey 感覺立即啟動!
我學到的一件事是,只要有恐懼和逃避,這正是需要一些過度精力充沛的懶惰的地方。 退後一步。讓它死掉簡單,擺脫重複的邏輯和或代碼的重點和大量。編寫函數以執行整個充滿測試的資料夾
// test folder of tests and fail entire run if any fail.
public void testFolder(File testfolder, Function<IN, OUT> converter) {
for (File test: testfolder.listFiles(testFileFilter)) {
if (!testSingle(test, converter)) {
fail("expected != actual - actual " +
"results saved in .actual file");
};
}
}
那麼這個測試Single函數呢?非常簡單,在 部落格 .
// test a single test
private boolean testSingle(File test, Function converter) {
IN input = loadInput(test);
OUT actual = converter.apply(input);
OUT expected = null;
// only create if no expected file or result is different.
File actualFile = new File(test.getParent(),
test.getName() + ".actual");
try {
expected = loadOutput(new File(test.getParent(),
test.getName()
+ ".expected"));
} catch (FileNotFoundException ex) {
// we haven't got expected file - no biggie
// we can turn this into an expected file once
// satisfied with it.
storeResult(actual, actualFile);
}
return false;
// we've got something to compare
if (!actual.equals(expected)) {
// fail and save the actual file for command
// line diffing
storeResult(actual, actualFile);
return false;
}
return true;
}
這種方法的雜項好處
對於基於文字和或 ascii 的文件,diff 實用程式可立即用於比較測試失敗
您不必編寫測試代碼來生成預期輸出。只需將範例記錄到測試資料夾,執行測試,並將實際輸出產生到具有 .實際延伸名的新檔案中
您可以立即通過導致生產中出現問題的記錄運行代碼。同樣,將有問題的記錄放入測試資料夾中並運行測試。
如果您的團隊決定構建一個全新的轉換器或使用其他 json 庫,則所有測試都表示為語言獨立檔。 你可以把它們向前推進。
要提前獲得的東西
首先,請注意使轉換邏輯成為無狀態的。 從本質上講,需要重新修改涉及進程外調用的文檔轉換,以便將原始數據的檢索與對原始數據的檢索分開。
其次,在代碼模組或應用程式的生命週期中儘早開始執行此操作。 食慾通常相當微薄的迴旋和重新工作舊的噁心測試。
下一步
下一步是將此打包為開源測試包。誰知道呢,如果我們有點興趣的話,它甚至遲早會發生