Andy5
Andy5

Reputation: 2405

C# Reflection SetValue

I am trying to create a unit test to test a specific edge case, and I am using Reflection to get hold of a private property of a class.

Whilst I can use

 var getPrivateProperty = obj.GetType().GetProperty("somename", BindingFlags.Instance | BindingFlags.NonPublic);
 getPrivateProperty.SetValue(obj, newValue, null);

The issue I have is that the property is set as null in the class and is then set to an instance of object in a method. In my specific test I need to set this property to an instance of an object, but I am still getting the infamous error of

Object not set to an instance of an object". I have tried this:

getPrivateProperty.SetValue(obj, new List<string>() {item, item2}, null);

Is there a way to set the property to be an instance of an object in order to complete my test?

Upvotes: 0

Views: 556

Answers (2)

Dustin Kingen
Dustin Kingen

Reputation: 21245

To avoid fragile reflection consider using the InternalsVisibleToAttribute with your test project.

Put the attribute in a well known location in your project. Somewhere like App_Start in ASP.NET 4 or the project root in ASP.NET Core.

AssemblyAttributes.cs

[assembly:System.Runtime.CompilerServices.InternalsVisibleTo("SomeProject.Tests")]

Then mark your private field as internal.

public class Foo
{
    internal string Bar;

    public void MethodThatUsesBar()
    {
    }
}

Now the Test project can reference the internal field.

public class FooTests
{
    public void TestMethodThatUsesBar()
    {
        var foo = new Foo { Bar = "This works now" };
        foo.MethodThatUsesBar();
        // Some Assertion
    }
}

Another way is to use the PrivateObject from Microsoft.VisualStudio.TestTools.UnitTesting.

public class FooTests
{
    public void TestMethodThatUsesBar()
    {
        var foo = new Foo();
        var fooWrapper = new PrivateObject(foo);
        fooWrapper.SetField("Bar", "This works too.");

        foo.MethodThatUsesBar();

        // Some Assertion
    }
}

Upvotes: 1

Formentz
Formentz

Reputation: 1193

I tried with this code:

public class Foo
{
    private List<string> somename { get; set; }
}

and then:

var foo = new Foo();
var fooType = foo.GetType();
var somenameProperty = fooType.GetProperty("somename", BindingFlags.Instance | BindingFlags.NonPublic);
somenameProperty.SetValue(foo, new List<string>() { "abc", "def" }, null);

and it works, but, as suggested in the comments, if you change the declaration of the 'somename' property to become a field, then 'somenameProperty' will be null because you should use GetField instead of GetProperty:

public class Foo
{
    private List<string> somename;
}

and then:

var foo = new Foo();
var fooType = foo.GetType();
var somenameField = fooType.GetField("somename", BindingFlags.Instance | BindingFlags.NonPublic);
somenameField.SetValue(foo, new List<string>() { "abc", "def" });

Upvotes: 0

Related Questions