2017-09-14 256 views
0

我想创建一个单元测试来测试一个特定的边界情况,并且我正在使用Reflection来获得一个类的私有属性。C#反射SetValue

虽然我可以用

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

我的问题是,该属性设置在类为空,然后设置为对象的方法的实例。在我具体的测试,我需要这个属性设置为对象的实例,但我仍然得到不设置到对象”的实例

对象的臭名昭著的错误,我已经试过这样:

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

有没有一种方法来设置属性为一个对象的实例,以完成我的测试?

+2

标记属性内部并使用['InternalsVisibleToAttribute'](https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute。 aspx)与您的测试项目。 – Romoku

+0

找出什么是空的,不要给它一个null。 –

+2

你可以发布一个[mcve]包括你正在反思的类吗?调试反射问题很困难,不知道你在做什么。 –

回答

1

为了避免脆弱的反射考虑使用InternalsVisibleToAttribute与你的测试项目。

将该属性放置在项目中众所周知的位置。某处像ASP.NET 4中的App_Start或ASP.NET Core中的项目根目录。

AssemblyAttributes.cs

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

然后标记您的private场为internal

public class Foo 
{ 
    internal string Bar; 

    public void MethodThatUsesBar() 
    { 
    } 
} 

现在测试项目可以引用internal字段。

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

另一种方式是从Microsoft.VisualStudio.TestTools.UnitTesting使用PrivateObject

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 
    } 
} 
+0

他正试图设置私人财产,而不是内部财产。不过,这是一个更好的解决方案。 – thisextendsthat

0

我试着用这个代码:

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

然后:

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

和它的作品,但是,作为意见建议,如果你改变的声明“ somename'属性成为字段,则'somenameProperty'将为空,因为您应该使用GetField而不是GetProperty:

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

然后:

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