[英]How to effectively test a fixed length flat file parser using MSpec?
我有這個方法簽名: List<ITMData> Parse(string[] lines)
ITMData
有 35 個屬性。
您將如何有效地測試這樣的解析器?
問題:
編輯
我將方法簽名更改為ITMData Parse(string line)
。
測試代碼:
[Subject(typeof(ITMFileParser))]
public class When_parsing_from_index_59_to_79
{
private const string Line = ".........";
private static ITMFileParser _parser;
private static ITMData _data;
private Establish context = () => { _parser = new ITMFileParser(); };
private Because of = () => { _data = _parser.Parse(Line); };
private It should_get_fldName = () => _data.FldName.ShouldBeEqualIgnoringCase("HUMMELDUMM");
}
編輯 2
我仍然不確定是否應該只測試每個 class 的一個屬性。 在我看來,這讓我可以為規范提供更多信息,即當我解析從索引 59 到索引 79 的單行時,我得到了 fldName。 如果我測試一個 class 中的所有屬性,我會丟失此信息。 我是否過度指定了我的測試?
我的測試現在看起來像這樣:
[Subject(typeof(ITMFileParser))]
public class When_parsing_single_line_from_ITM_file
{
const string Line = ""
static ITMFileParser _parser;
static ITMData _data;
Establish context = () => { _parser = new ITMFileParser(); };
private Because of = () => { _data = _parser.Parse(Line); };
It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
...
}
我應該加載整個文件(我可以使用 System.IO)嗎?
如果你這樣做,它就不再是一個單元測試——它變成了一個集成或回歸測試。 如果您希望它顯示單元測試不會顯示的可能錯誤,您可以這樣做。 但這不太可能。
至少在開始時,您可能最好使用單元測試。
我應該將文件中的一行放入字符串常量中嗎?
如果您打算編寫多個使用相同輸入行的測試,那么當然可以。 但就個人而言,我可能傾向於編寫一堆不同的測試,每個測試都傳遞不同的輸入字符串。 那時,沒有太多理由制作一個常量(除非它是一個局部常量,在測試方法中聲明)。
我應該測試一條或多條線嗎?
您沒有指定,但我假設您的 output 與您的輸入是一對一的——也就是說,如果您傳入三個字符串,您將返回三個ITMData
。 在這種情況下,對多線測試的需求將受到限制。
幾乎總是值得測試退化的情況,在這種情況下它將是一個空字符串數組(零行)。 並且可能值得至少進行一次包含多行的測試,這樣您就可以確保迭代中沒有愚蠢的錯誤。
但是,如果您的 output 與您的輸入是一對一的,那么您確實有另一種方法想要退出——您應該有一個ParseSingleLine
方法。 那么你的Parse
只不過是迭代行並調用ParseSingleLine
。 您仍然需要對 Parse 進行少量測試,但您的大部分測試將集中在ParseSingleLine
。
如果我遇到這樣的問題,我通常會這樣做:
提前一個簡短的免責聲明:我想我會更多 go 沿着“集成測試”或“作為一個整體測試解析器”路線而不是測試單個行。 在過去,我不止一次遇到過很多實現細節泄漏到我的測試中的情況,當我更改實現細節時,我不得不經常更改測試。 我猜是超規格的典型案例;-/
我通常會嘗試考慮常見的成功和失敗場景,以及邊緣情況。 需求也有助於設置適當的用例。 考慮使用Pex枚舉各種場景。
關於您的新問題:
我應該測試 ITMData 的每個屬性還是應該測試整個 object?
如果您想安全起見,您可能應該至少有一個測試來檢查每個屬性是否匹配。
我的測試命名如何?
關於這個話題有很多討論,比如這個。 一般規則是在單元測試 class 中有多種方法,每種方法都旨在測試特定的東西。 在你的情況下,它可能是這樣的:
public void Check_All_Properties_Parsed_Correctly(){.....}
public void Exception_Thrown_If_Lines_Is_Null(){.....}
public void Exception_Thrown_If_Lines_Is_Wrong_Length(){.....}
因此,換句話說,測試您認為解析器“正確”的確切行為。 完成此操作后,您在更改解析器代碼時會感到更加輕松,因為您將擁有一個全面的測試套件來檢查您沒有破壞任何東西。 記住要經常進行實際測試,並在進行更改時保持測試更新! MSDN上有一個關於單元測試和測試驅動開發的相當好的指南。
一般來說,我認為您可以通過谷歌搜索找到大多數問題的答案。 還有幾本關於測試驅動開發的優秀書籍,它們不僅會帶您了解TDD 的原理,還可以帶您了解為什么。 如果您相對編程語言不可知,我會推薦 Kent Beck 的Test Driven Development By Example ,否則就像Microsoft .NET 中的 Test-Driven Development 。 這些應該會讓你很快走上正確的軌道。
編輯:
我是否過度指定了我的測試?
在我看來,是的。 具體來說,我不同意你的下一行:
如果我測試一個 class 中的所有屬性,我會丟失此信息。
您究竟以何種方式丟失信息? 假設有兩種方法可以進行此測試,除了每次測試都有一個新的 class :
CheckPropertyX
、 CheckPropertyY
等。當您運行測試時,您將確切地看到哪些字段通過了,哪些字段失敗了。 這顯然滿足了您的要求,盡管我會說這仍然是矯枉過正。 我會 go 與選項 2: Assert.AreEqual("test1", myObject.PropertyX, "Property X was incorrectly parsed");
Assert.AreEqual("test2", myObject.PropertyY, "Property Y was incorrectly parsed");
當其中一個失敗時,您將知道哪條線失敗了。 修復相關錯誤並重新運行測試后,您將查看是否有任何其他屬性失敗。 這通常是大多數人采用的方法,因為創建 class 甚至每個屬性的方法會導致代碼過多,並且需要進行太多工作來保持最新狀態。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.