Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用私有setter将模拟接口分配给属性进行单元测试?_C#_Unit Testing_Reflection_Moq_Mef - Fatal编程技术网

C# 如何使用私有setter将模拟接口分配给属性进行单元测试?

C# 如何使用私有setter将模拟接口分配给属性进行单元测试?,c#,unit-testing,reflection,moq,mef,C#,Unit Testing,Reflection,Moq,Mef,基本上,我使用MEF导出类并获得“公共”导入。当我想测试这些类时,我可以创建IFoo的模拟接口,但是如何使用privatesetter将其实际应用到其中呢?MEF能够以某种方式处理它,我不确定如何测试我的DoSomething方法。我认为唯一的方法是使用反射。我认为唯一的方法是使用反射。MyAbstractClass依赖于IFoo,但您没有明确说明它。应添加构造函数以使依赖项显式: [InheritedExport(typeof(MyAbstractClass)) public abstract

基本上,我使用MEF导出类并获得“公共”导入。当我想测试这些类时,我可以创建IFoo的模拟接口,但是如何使用privatesetter将其实际应用到其中呢?MEF能够以某种方式处理它,我不确定如何测试我的DoSomething方法。

我认为唯一的方法是使用反射。

我认为唯一的方法是使用反射。

MyAbstractClass
依赖于
IFoo
,但您没有明确说明它。应添加构造函数以使依赖项显式:

[InheritedExport(typeof(MyAbstractClass))
public abstract class MyAbstractClass
{
    [Import] protected IFoo Foo { get; private set; }
}

public sealed class MyClass : MyAbstractClass
{
    public void DoSomething()
    {
        if (Foo == null) throw new Exception();

        var = Foo.GetBar();
        //etc.
    }
}
现在您可以使用mock轻松地测试它

所以,我把你们的课改写成这样:

public MyAbstractClass(IFoo foo) { this.Foo = foo; }
[InheritedExport(typeof(MyAbstractClass))
公共抽象类MyAbstractClass{
私有只读IFoo;
公共伊福{
得到{
Contract.sure(Contract.Result()!=null);
返回此.foo;
}
}
受保护的MyAbstractClass(IFoo-foo){
Contract.Requires(foo!=null);
this.foo=foo;
}
}
公共类MyClass:MyAbstractClass
{
[导入构造函数]
公共MyClass(IFoo-foo):基(foo){}
}

否则,您必须使用反射来获取私有setter。这太恶心了。

MyAbstractClass
依赖于
IFoo
,但您没有将其显式化。您应该添加一个构造函数以使依赖显式化:

[InheritedExport(typeof(MyAbstractClass))
public abstract class MyAbstractClass
{
    [Import] protected IFoo Foo { get; private set; }
}

public sealed class MyClass : MyAbstractClass
{
    public void DoSomething()
    {
        if (Foo == null) throw new Exception();

        var = Foo.GetBar();
        //etc.
    }
}
现在您可以使用mock轻松地测试它

所以,我把你们的课改写成这样:

public MyAbstractClass(IFoo foo) { this.Foo = foo; }
[InheritedExport(typeof(MyAbstractClass))
公共抽象类MyAbstractClass{
私有只读IFoo;
公共伊福{
得到{
Contract.sure(Contract.Result()!=null);
返回此.foo;
}
}
受保护的MyAbstractClass(IFoo-foo){
Contract.Requires(foo!=null);
this.foo=foo;
}
}
公共类MyClass:MyAbstractClass
{
[导入构造函数]
公共MyClass(IFoo-foo):基(foo){}
}

否则,您必须使用反射来获取私有setter。这太恶心了。

尝试在构造函数中传递它:

[InheritedExport(typeof(MyAbstractClass))
public abstract class MyAbstractClass {
    private readonly IFoo foo;
    public IFoo Foo {
        get {
            Contract.Ensures(Contract.Result<IFoo>() != null);  
            return this.foo;
        }
    }

    protected MyAbstractClass(IFoo foo) {
        Contract.Requires(foo != null);
        this.foo = foo;
    }
}

public class MyClass : MyAbstractClass
{
    [ImportingConstructor]
    public MyClass(IFoo foo) : base(foo) { }
}

并将抽象类中的“私有集”更改为“受保护集”。

尝试在构造函数中传递它:

[InheritedExport(typeof(MyAbstractClass))
public abstract class MyAbstractClass {
    private readonly IFoo foo;
    public IFoo Foo {
        get {
            Contract.Ensures(Contract.Result<IFoo>() != null);  
            return this.foo;
        }
    }

    protected MyAbstractClass(IFoo foo) {
        Contract.Requires(foo != null);
        this.foo = foo;
    }
}

public class MyClass : MyAbstractClass
{
    [ImportingConstructor]
    public MyClass(IFoo foo) : base(foo) { }
}

并将抽象类中的“私有集”更改为“受保护集”。

我相信使用MS Moles框架可以实现这一点:


我相信您可以通过MS Moles框架实现这一点:


反射是最好的方法。我喜欢在基本测试程序集中创建一个扩展方法,它具有访问/设置私有成员等有用功能

另一种选择(如果可以将setter设置为受保护的而不是私有的-这里可能是这种情况,也可能不是这种情况,但是如果您确实有一个具有类似愿望的受保护成员)让你的测试子类被测试的类。这感觉很脏,看起来不是一个好主意,但我想不出一个实际的原因为什么它不好,并且可以实现这里的目标

class MyClass : MyAbstractClass
{
    public MyClass (IFoo foo)
    {
        Foo = foo;
    }
}
公共静态类ReflectionExtensions
{
公共静态T GetPrivateFieldValue(此对象实例,字符串字段名)
{
var field=instance.GetType().GetField(fieldName,BindingFlags.instance | BindingFlags.NonPublic | BindingFlags.Public);
如果(字段!=null)
{
return(T)field.GetValue(实例);
}
抛出新ArgumentException(“无法找到指定的字段。”,“fieldName”);
}
公共静态void SetReadonlyProperty(此对象实例,字符串propertyName,对象值)
{
instance.GetType().GetProperty(propertyName).SetValue(instance,value,null);
}
公共静态void SetStaticCreadonlyProperty(此类型、字符串属性名称、对象值)
{
type.GetProperty(propertyName).GetSetMethod(true).Invoke(null,new[]{value});
}
}

反射是最好的方法。我喜欢在基本测试程序集中创建一个扩展方法,它具有访问/设置私有成员等有用功能

另一种选择(如果可以将setter设置为受保护的而不是私有的-这里可能是这种情况,也可能不是这种情况,但是如果您确实有一个具有类似愿望的受保护成员)让你的测试子类被测试的类。这感觉很脏,看起来不是一个好主意,但我想不出一个实际的原因为什么它不好,并且可以实现这里的目标

class MyClass : MyAbstractClass
{
    public MyClass (IFoo foo)
    {
        Foo = foo;
    }
}
公共静态类ReflectionExtensions
{
公共静态T GetPrivateFieldValue(此对象实例,字符串字段名)
{
var field=instance.GetType().GetField(fieldName,BindingFlags.instance | BindingFlags.NonPublic | BindingFlags.Public);
如果(字段!=null)
{
return(T)field.GetValue(实例);
}
抛出新ArgumentException(“无法找到指定的字段。”,“fieldName”);
}
公共静态void SetReadonlyProperty(此对象实例,字符串propertyName,对象值)
{
instance.GetType().GetProperty(propertyName).SetValue(instance,value,null);
}
公共静态void SetStaticCreadonlyProperty(此类型、字符串属性名称、对象值)
{
type.GetProperty(propertyName).GetSetMethod(true).Invoke(null,new[]{value});
}
}

如果要保留MEF导入,最简单的方法是在每个属性上使用
导入构造函数属性
而不是
导入属性
s

public static class ReflectionExtensions
{
    public static T GetPrivateFieldValue<T>(this object instance, string fieldName)
    {
        var field = instance.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
        if (field != null)
        {
            return (T) field.GetValue(instance);
        }
        throw new ArgumentException("The field specified could not be located.", "fieldName");
    }

    public static void SetReadonlyProperty(this object instance, string propertyName, object value)
    {
        instance.GetType().GetProperty(propertyName).SetValue(instance, value, null);
    }

    public static void SetStaticReadonlyProperty(this Type type, string propertyName, object value)
    {
        type.GetProperty(propertyName).GetSetMethod(true).Invoke(null, new[] { value });
    }
}
}

这个解决方案有点糟糕,因为现在你必须让所有从MyAbstractClass扩展的类都使用一个
ImportingConstructorAttribute
并调用
base()
。如果你的抽象类被到处使用,尤其是当它决定添加另一个导入的属性时,这可能会变得非常糟糕