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

时间:2022-05-27 23:06:03

I'm testing a class that is part of a hierarchy. I've been setting up my test classes with the object under test, and a PrivateObject to allow access to that object. I'm getting exceptions when I attempt to access private members of the parent class.

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

The only workaround I've found so far is to pass a PrivateType specifying the base class to the PrivateObject constructor, but then it doesn't work on private members of the subclass.

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

Is there some way I can do this, perhaps by using the binding flags parameter on the Get* methods of Private object?

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

I did try using the automatically-generated Accessor classes (right-click in the main class, Create Private Accessor). However, that's worse: It shows a property I can read, but it throws the same exception as PrivateObject does, and there's no other options I can use (binding flags or whatnot) to fix the exception.

我尝试使用自动生成的Accessor类(右键单击主类,Create Private Accessor)。但是,情况更糟:它显示了我可以读取的属性,但它抛出与PrivateObject相同的异常,并且没有其他选项可以使用(绑定标志或诸如此类)来修复异常。

Here's my sample test code. I'd like there to be some way to construct and use the PrivateObject to retrieve both fields.

这是我的示例测试代码。我希望有一些方法来构造和使用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 个解决方案

#1


31  

I didn't find the answer, so this is what I ended up doing. I created PrivateObjects for each level of the class's hierarchy, and I just need to be careful when writing test cases that I use the proper one.

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

#2


9  

This likely isn't the answer you want...but you shouldn't be testing both classes in one method in the first place. You should only ever be testing one class at a time. If you feel the need to do this, then I'd guess that your code needs refactoring. But as I don't know your real-life code problem, I can't say for sure

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

#3


1  

PrivateObject is a bit on the "dumb" side when it comes to handling inheritance. Unfortunately, its methods are not virtual, so there's no easy way to change this behaviour. You essentially have two options: either live with the limitations or create your own private accessor helper that can handle inherited members transparently.

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

#4


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");

#5


1  

As André Pena wrote. Why would you like to test private members of the Baseclass through the Subclass. You wouldn't have access to these members in normal code of your Subclass either. You have to make the Properties members protected to have access to them from the Subclass.

正如安德烈佩纳所写的那样。您为什么要通过子类测试Baseclass的私有成员。您也无法在子类的普通代码中访问这些成员。您必须使属性成员受到保护才能从子类访问它们。

Then you can also test these Members with the PrivateObject.

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

#6


1  

I wanted to do same thing and I made this extension methods. Now it works well. My initial idea is from your post. Thank you!

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

https://github.com/cactuaroid/PrivateObjectExtensions

https://github.com/cactuaroid/PrivateObjectExtensions

What it's doing basically is finding member owner by Type.GetFields() and Type.GetProperties() recursively, and then create PrivateObject (or PrivateType) as correct type to access the member.

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

#7


0  

Use PrivateType to specify the desired type and use a different constructor of PrivateObject:

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

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

#1


31  

I didn't find the answer, so this is what I ended up doing. I created PrivateObjects for each level of the class's hierarchy, and I just need to be careful when writing test cases that I use the proper one.

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

#2


9  

This likely isn't the answer you want...but you shouldn't be testing both classes in one method in the first place. You should only ever be testing one class at a time. If you feel the need to do this, then I'd guess that your code needs refactoring. But as I don't know your real-life code problem, I can't say for sure

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

#3


1  

PrivateObject is a bit on the "dumb" side when it comes to handling inheritance. Unfortunately, its methods are not virtual, so there's no easy way to change this behaviour. You essentially have two options: either live with the limitations or create your own private accessor helper that can handle inherited members transparently.

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

#4


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");

#5


1  

As André Pena wrote. Why would you like to test private members of the Baseclass through the Subclass. You wouldn't have access to these members in normal code of your Subclass either. You have to make the Properties members protected to have access to them from the Subclass.

正如安德烈佩纳所写的那样。您为什么要通过子类测试Baseclass的私有成员。您也无法在子类的普通代码中访问这些成员。您必须使属性成员受到保护才能从子类访问它们。

Then you can also test these Members with the PrivateObject.

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

#6


1  

I wanted to do same thing and I made this extension methods. Now it works well. My initial idea is from your post. Thank you!

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

https://github.com/cactuaroid/PrivateObjectExtensions

https://github.com/cactuaroid/PrivateObjectExtensions

What it's doing basically is finding member owner by Type.GetFields() and Type.GetProperties() recursively, and then create PrivateObject (or PrivateType) as correct type to access the member.

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

#7


0  

Use PrivateType to specify the desired type and use a different constructor of PrivateObject:

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

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