![](/img/trans.png)
[英]Is it considered bad practice to use InternalsVisibleTo for Unit Test Code?
[英]Is it bad practice to use reflection to do complex object assertion for a unit test?
我正在閱讀這個主題 ,這是關於使用反射來測試私有變量...
但我的單元測試中沒有這樣的問題,我的代碼完全可以測試。
唯一的問題是我想通了,對具有預期結果的復雜對象的每個屬性進行斷言時非常耗時; 特別是對於復雜對象的列表。
由於它是一個復雜的對象,除非我為每個對象實現IEquality
,否則執行正常的Assert.AreEqual
不會給我一個正確的結果。
但即使我這樣做,也不會告訴我在斷言期間哪個屬性/字段的名稱,期望值和實際值。
正確地說,我們手動將每個屬性值放入一個列表並執行單個CollectionAssertion
,但這仍然非常耗時,並且當斷言發生時它只告訴我元素值的索引不相等; 它不會告訴我屬性名稱。 這使得調試變得非常困難(我必須進入調試模式並查看集合中的元素)。
所以我想知道,如果我編寫一個遞歸反射方法,它將對兩個復雜對象進行斷言,它將告訴我每個屬性名稱,期望值,實際值。
這是一種好的做法還是不好的做法?
我發現很多人甚至不會考慮反思,但它有它的位置。 它在性能,類型安全等方面肯定存在缺陷,正如其他海報所述,但我認為單元測試是一個很好的使用場所。 只要它成功完成。
當您不擁有在屬性中使用的所有類型時,嘗試在所有對象上強制執行等同實現會進入牆。 實現一百個迷你比較器類與手動寫出斷言一樣耗時。
在過去,我編寫了一個擴展方法,可以執行您所描述的操作:
我的測試在任何時候都不關心屬性名稱,因此重構重構並不重要。 實際上,會自動找到新屬性,而忘記刪除的屬性。
我從來沒有將它用於非常復雜的物體,但是它與我擁有的物體配合得很好,而不會減慢我的測試速度。
所以我認為在單元測試中可以隨意使用Reflection。
編輯:我會嘗試為你挖掘我的方法。
在我看來,使用Reflection不是一個很好的選擇。 使用Reflection意味着我們在編譯時失去了類型安全性。 而且,在使用Reflection之后,可能(通常)通過程序集的元數據進行不區分大小寫的字符串搜索。 這導致性能下降。 考慮到這些方面,我認為拆分原始類型(如oleksii所推薦)是一種很好的方法。
另一種方法可以是使用純訪問器方法編寫單獨的測試,以測試單獨的屬性集。 這可能不適用於所有情況。 但是,在某些情況下確實如此。
例如:如果我有一個Customer類,我可以編寫一個測試來檢查Address-type字段; 我可以編寫另一個測試來檢查訂單類型字段等等。
在正常情況下,您不應該需要反射來做與測試相關的任何事情 。 在回答您鏈接的問題時提到了這一點:
反思應該只是最后的手段
如果需要檢查復雜對象是否相等, 請在單元測試中實現此類等式檢查 。 純粹用於單元測試目的的額外代碼沒有錯:
public void ComplexObjectsAreEqual()
{
var first = // ...
var second = // ...
AssertComplexObjectsAreEqual(first, second);
}
private void AssertComplexObjectsAreEqual(ComplexObject first,
ComplexObject second)
{
Assert.That(first.Property1, Is.EqualTo(second.Property1),
"Property1 differs: {0} vs {1}", first.Property1, second.Property1);
// ...
}
您不應該將單元測試視為其他代碼 。 如果需要編寫某些東西以使它們更具可讀性,清潔,可維護 - 寫下來。 它與其他地方的代碼相同。 您是否會通過生產代碼中的反射來比較對象?
我想說使用反射進行簡單的單元測試有很多正當理由。 引用https://github.com/kbilsted/StatePrinter
手動單元測試的問題
當我一遍又一遍地打字並重新輸入時:Assert.This,Assert。那,......不禁想知道為什么計算機無法為我自動化這些東西。 所有那些不必要的打字需要時間並耗盡我的精力。
使用Stateprinter時,只要預期值和實際值不匹配,就會為您生成斷言。
當代碼更改時,例如通過向類添加字段,您需要在某些測試中添加斷言。 但是,找到一個完全手動的過程。 在沒有人對所有類進行完整概述的較大項目中,所需的更改不會在所有應該執行的地方執行。
將代碼從一個分支合並到另一個分支時會出現類似的情況。 假設您將發布分支中的錯誤修復或功能合並到開發分支,我一遍又一遍地觀察到代碼被合並,所有測試都運行然后提交合並。 人們忘記重新訪問並仔細檢查整個測試套件,以確定開發分支上是否存在測試,而不是合並發生的分支上的測試,相應地調整這些測試。
使用Stateprinter時,會比較對象圖而不是單個字段。 因此,當創建新字段時,所有相關測試都會失敗。 您可以將打印調整到特定字段,但是您無法自動檢測圖表中的更改。
通過對測試類,測試方法和測試元素的標准命名的良好命名,您可以獲得很長的成功。 但是,沒有命名約定可以彌補斷言創建的視覺混亂。 當索引用於從列表或詞典中挑選元素時,會添加進一步的混亂。 並且在將它與for,foreach循環或LINQ表達式結合使用時,不要讓我開始。
使用StatePrinter時,會比較對象圖而不是單個字段。 因此,測試中不需要邏輯來挑選數據。
當我讀下面的測試時。 想想這里真正重要的是什么
Assert.IsNotNull(result, "result");
Assert.IsNotNull(result.VersionData, "Version data");
CollectionAssert.IsNotEmpty(result.VersionData)
var adjustmentAccountsInfoData = result.VersionData[0].AdjustmentAccountsInfo;
Assert.IsFalse(adjustmentAccountsInfoData.IsContractAssociatedWithAScheme);
Assert.AreEqual(RiskGroupStatus.High, adjustmentAccountsInfoData.Status);
Assert.That(adjustmentAccountsInfoData.RiskGroupModel, Is.EqualTo(RiskGroupModel.Flexible));
Assert.AreEqual("b", adjustmentAccountsInfoData.PriceModel);
Assert.IsTrue(adjustmentAccountsInfoData.IsManual);
什么時候蒸餾我們想要表達的是什么
adjustmentAccountsInfoData.IsContractAssociatedWithAScheme = false
adjustmentAccountsInfoData.Status = RiskGroupStatus.High
adjustmentAccountsInfoData.RiskGroupModel = RiskGroupModel.Flexible
adjustmentAccountsInfoData.PriceModel = "b"
adjustmentAccountsInfoData.IsManual = true
當業務對象的字段數量增加時,相反的情況對於測試的可靠性來說也是如此。 是否覆蓋了所有領域? 字段是否被錯誤地多次比較? 還是反對錯誤的領域? 當你必須在一個對象上做25個斷言時,你就會知道痛苦,並且精心確保在正確的字段中檢查正確的字段。 然后審稿人必須經歷相同的練習。 為什么這不是自動化的?
使用StatePrinter時,會比較對象圖而不是單個字段。 您知道所有字段都已覆蓋,因為所有字段都已打印。
恕我直言,這是一個不好的做法,因為:
對我來說,這看起來好像是在試圖堵塞一個洞,而不是解決問題。 為了解決這個問題,我可以建議將一個大而復雜的類分成一組較小的類。 如果您有許多屬性 - 將它們分組到單個類中
這樣的課
class Foo
{
T1 Prop1 {get; set;}
T2 Prop2 {get; set;}
T3 Prop3 {get; set;}
T4 Prop4 {get; set;}
}
會成為
class Foo
{
T12 Prop12 {get; set;}
T34 Prop34 {get; set;}
}
class T12
{
T1 Prop1 {get; set;}
T2 Prop2 {get; set;}
}
class T34
{
T3 Prop3 {get; set;}
T4 Prop4 {get; set;}
}
注意, Foo
現在只有一個屬性(即“分組”表示)。 如果您可以以某種方式對屬性進行分組,那么任何狀態更改都將本地化為特定組 - 您的任務將變得更加簡化。 然后,您可以斷言“分組”屬性等於預期狀態。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.