2011-03-22 116 views
22

我正在測試作爲層次結構一部分的類。我一直在設置我的測試類與測試對象,並允許訪問該對象的PrivateObject。當我嘗試訪問父類的私有成員時,我收到異常。如何使用PrivateObject訪問我的類和它的父類的私有成員?

到目前爲止,我發現的唯一解決方法是將指定基類的PrivateType傳遞給PrivateObject構造函數,但它不適用於子類的私有成員。

有什麼辦法可以做到這一點,也許通過在私有對象的Get *方法上使用綁定標誌參數?

我嘗試使用自動生成的Accessor類(右鍵單擊主類Create Private Accessor)。然而,情況更糟糕:它顯示了一個我可以讀取的屬性,但它引發了與PrivateObject相同的異常,並且沒有其他選項可以用來修復異常(綁定標誌或其他選項)。

這是我的示例測試代碼。我希望有一些方法來構建和使用PrivateObject來檢索這兩個字段。

public class BaseClass 
{ 
    private int one = 1; 
} 

public class SubClass : BaseClass 
{ 
    private int two = 2; 
} 

[TestClass] 
public class UnitTest1 
{ 
    BindingFlags flags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; 

    [TestMethod] 
    public void TestMethod1() 
    { 
     SubClass test = new SubClass(); 
     PrivateObject priv = new PrivateObject(test); 

     Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("one", flags)); // System.MissingMethodException: Method 'PrivateObjectTester.SubClass.one' not found. 
     Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("two", flags)); 
    } 

    [TestMethod] 
    public void TestMethod2() 
    { 
     SubClass test = new SubClass(); 
     PrivateObject priv = new PrivateObject(test, new PrivateType(typeof(BaseClass))); 

     Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("one", flags)); 
     Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("two", flags)); // System.MissingMethodException: Method 'PrivateObjectTester.BaseClass.two' not found. 
    } 
} 
+1

正如旁註所示,您可以使用PrivateObject訪問受保護的成員 – 2012-09-04 19:07:27

回答

28

我沒有找到答案,所以這就是我最終做的。我爲類的層次結構的每個級別創建了PrivateObjects,在編寫使用正確的測試用例時,我只需要小心。

public class BaseClass 
{ 
    private int one = 1; 
} 

public class SubClass : BaseClass 
{ 
    private int two = 2; 
} 

[TestClass] 
public class UnitTest1 
{ 
    [TestMethod] 
    public void TestMethod() 
    { 
     SubClass test = new SubClass(); 
     PrivateObject privSub = new PrivateObject(test, new PrivateType(typeof(SubClass))); 
     PrivateObject privBase = new PrivateObject(test, new PrivateType(typeof(BaseClass))); 

     Assert.AreNotEqual<int>(0, (int)privBase.GetFieldOrProperty("one")); 
     Assert.AreNotEqual<int>(0, (int)privSub.GetFieldOrProperty("two")); 
    } 
} 
+0

這是實現它的正確方法。 – Thought 2017-12-04 17:37:52

8

這可能不是您想要的答案......但您不應該在一種方法中首先測試兩個類。你應該一次只能測試一個課程。如果你覺得需要這樣做,那麼我猜你的代碼需要重構。但是因爲我不知道你的真實代碼問題,所以我不能肯定地說

+2

我沒有真正測試兩個類,我正在測試一個類,以及它的基類。在我的情況下,我正在測試一些清理行爲:當對象清理自己時,我檢查所有清理任務是否正確發生,其中一些在基礎中,一些在子類中。你是對的,理想情況下,我應該自己測試基類清除,但是這個測試的一部分是測試異常清除,只有在這個特定的子類中才會發生。 – 2011-04-15 18:36:33

1

當涉及到處理繼承問題時,PrivateObject在「愚蠢的」一面。不幸的是,它的方法不是虛擬的,所以沒有簡單的方法來改變這種行爲。你基本上有兩個選擇:或者生活在限制之中,或者創建你自己的私人訪問器助手,它可以透明地處理繼承的成員。

1
// create an instance of class SearchPlanogramsBuilder: 
SearchPlanogramsBuilder searchPlanogramBuilder = new SearchPlanogramsBuilder(); 

// executing the method BuildSearchParameters(return type is void) with input searchPlanoGramsFilters: 
searchPlanogramBuilder.BuildSearchParameters(searchPlanoGramsFilters); 

// create privateobject and pass instance created for the class: 
PrivateObject helperobject1 = new PrivateObject(searchPlanogramBuilder); 

// type cast exactly as parameter(which is private variable) in the method: 
Collection<string> parameter = (Collection<string>)helperobject1.GetFieldOrProperty("parameters"); 
1

安德烈·佩納寫道。爲什麼你想通過Subclass測試Baseclass的private成員。您無法在您的子類的正常代碼中訪問這些成員。您必須使Properties成員protected能夠從子類訪問它們。

然後你也可以使用PrivateObject測試這些成員。

+0

考慮您正在爲抽象類中的公共功能編寫測試。爲了測試這個類,你創建了一個你可以實例化的派生模擬類。在這種情況下,您可能仍然想要使用私有變量的值(例如,由UI綁定的屬性,該屬性沒有公共/受保護的setter)。 我不同意改變成員以適應測試的方便性就是答案。 – kodjeff1 2014-08-04 19:38:45

1

我想做同樣的事情,我做了這種擴展方法。現在它運作良好。我最初的想法是從你的帖子。謝謝!

https://github.com/cactuaroid/PrivateObjectExtensions

它在做什麼基本上是由Type.GetFields()Type.GetProperties()尋找成員所有者遞歸,然後創建PrivateObject(或PrivateType)爲正確類型訪問成員。

相關問題