如何使用PrivateObject访问我的类及其父级的私有成员?

时间:2011-03-22 19:53:56

标签: c# unit-testing mstest

我正在测试一个属于层次结构的类。我一直在使用被测对象设置我的测试类,并使用PrivateObject来访问该对象。当我尝试访问父类的私有成员时,我遇到异常。

到目前为止,我发现的唯一解决方法是将PrivateType指定基类传递给PrivateObject构造函数,但是它不适用于子类的私有成员。

有没有办法可以做到这一点,也许是通过在Private对象的Get *方法上使用binding flags参数?

我尝试使用自动生成的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.
    }
}

7 个答案:

答案 0 :(得分:31)

我没有找到答案,所以这就是我最终要做的事情。我为类的层次结构的每个级别创建了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"));
    }
}

答案 1 :(得分:9)

这可能不是您想要的答案......但您不应该首先在一种方法中测试这两个类。你应该一次只测试一个班级。如果你觉得有必要这样做,那么我猜你的代码需要重构。但由于我不知道你的现实代码问题,我不能肯定地说

答案 2 :(得分:1)

在处理继承时,PrivateObject有点“愚蠢”。不幸的是,它的方法不是虚拟的,因此没有简单的方法来改变这种行为。您基本上有两个选择:要么有限制,要么创建自己的私有访问者帮助程序,可以透明地处理继承的成员。

答案 3 :(得分: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");

答案 4 :(得分:1)

AndréPena写道。您为什么要通过子类测试基类的private成员。您也无法在子类的普通代码中访问这些成员。您必须使属性成员protected能够从子类访问它们。

然后您还可以使用PrivateObject测试这些成员。

答案 5 :(得分:1)

我想做同样的事情,我做了这个扩展方法。现在它运作良好。我最初的想法来自你的帖子。谢谢!

https://github.com/cactuaroid/PrivateObjectExtensions

它正在做的基本上是通过Type.GetFields()Type.GetProperties()递归查找成员所有者,然后创建PrivateObject(或PrivateType)作为访问该成员的正确类型。

答案 6 :(得分:0)

使用PrivateType指定所需类型并使用PrivateObject的其他构造函数:

var test = new SubClass();
var privateType = new PrivateType(typeof(BaseClass));
var privateObject = new PrivateObject(test, privateType);
// privateObject.GetFieldOrProperty("one", flags)