繁体   English   中英

重载受保护的通用方法单元测试,导致AmbiguousMatchException

[英]Overloaded protected generic Method Unit testing causing AmbiguousMatchException

我试图在代码重载签名中测试(使用Moq)重载受保护的通用方法:

protected void AutoMap<FromType, ToType>(IList<FromType> sources
                                         , IList<ToType> destinations)

protected void AutoMap<FromType, ToType>(FromType from
                                         , ToType to)

为了能够访问其中的第二种方法,我正在使用PrivateObject,然后通过反射调用方法:

a obj_a = new a();
b obj_b = new b();
PrivateObject o = new PrivateObject(controller);
o.Invoke("AutoMap"
         , new Type[] { typeof(a), typeof(b) }
         , new Object[] { obj_a, obj_b }
         , new Type[] { typeof(a), typeof(b) });

当我运行测试时,我得到了System.Reflection.AmbiguousMatchException,说找到了模糊匹配。

谁能告诉我如何正确执行此操作? 干杯K.

通常,您不应该测试受保护的方法。 仅应测试公共方法。 从单元测试的角度来看,受保护的方法应视为私有方法。

您应该测试实现类,并观察它是否按预期工作。 如果此类使用受保护/私有方法来完成任务-这是实现细节,并且实现可以随时更改而无需更改类的行为(请考虑重构)。

假设您有:

public abstract class Base
{
   public virtual int GetResult(int data)
   {
       var z = GetMoreData();
       return data*z;
   }
   protected int GetMoreData()
   {
      ///something
      return something;
    }
}

public class MyRealImplementation : Base
{
    public override int GetResult(int data)
    {
       //wahtever
    }
}

无法(或毫无意义)测试受保护的方法。 不知道被覆盖的GetResult是否会使用它(可能会或可能不会)。

唯一要测试的想法是GetResult是否返回预期的结果,而不是如何实现的。

在特定情况下,最好在接口后面抽象映射功能,以便对其进行模拟。

public interface IMapper
{
    AutoMap<FromType, ToType>(IList<FromType> sources, IList<ToType> destinations);
    oid AutoMap<FromType, ToType>(FromType from, ToType to);
}

在您的PrivateObject中注入该接口,并使用它代替受保护的方法。 这样,您将:

  1. 让您的班级/方法遵循单一责任原则
  2. 独立测试映射
  3. 使用模拟来测试您的私人课程

通常,每次很难编写单元测试时,通常这意味着类/方法做得太多。

尽管我同意Sunny提出的关于测试受保护方法的愚蠢回答 ,但这个问题使我很感兴趣,所以我尝试找出问题出在哪里。

问题是PrivateObject类的局限性,该类基本上只是一些反射方法的包装。 这是一个已知的限制,请在此处此处查看示例问题。

如果您真的想测试这样的方法,则需要自己使用这些反射方法。

//this is ugly, but the quickest way I could filter down to the overload that 
//doesn't take in the IList interface arguments
var method = typeof (YOUR_CONTROLLER_CLASS).GetMethods(
             BindingFlags.Instance | BindingFlags.NonPublic)
            .First(m => m.IsGenericMethod 
                && m.Name == "AutoMap" 
                && !m.GetParameters()[0].ParameterType.IsInterface);
var genericMethod = method.MakeGenericMethod(new[] {typeof (a), typeof (b)});
genericMethod.Invoke(controller, new object[]{ obj_a, obj_b });

希望能有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM