How can I use PrivateObject to access private memb

2019-01-17 03:50发布

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.

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.

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

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.

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

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条回答
孤傲高冷的网名
2楼-- · 2019-01-17 04:09

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

var test = new SubClass();
var privateType = new PrivateType(typeof(BaseClass));
var privateObject = new PrivateObject(test, privateType);
// privateObject.GetFieldOrProperty("one", flags)
查看更多
再贱就再见
3楼-- · 2019-01-17 04:10
// 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");
查看更多
Emotional °昔
4楼-- · 2019-01-17 04:10

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

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.

查看更多
一纸荒年 Trace。
5楼-- · 2019-01-17 04:14

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

查看更多
男人必须洒脱
6楼-- · 2019-01-17 04:17

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.

Then you can also test these Members with the PrivateObject.

查看更多
beautiful°
7楼-- · 2019-01-17 04:26

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.

查看更多
登录 后发表回答