用Moq嘲笑扩展方法

我有一个预先存在的接口…

public interface ISomeInterface { void SomeMethod(); } 

我已经扩展了这个内置使用混合…

 public static class SomeInterfaceExtensions { public static void AnotherMethod(this ISomeInterface someInterface) { // Implementation here } } 

我有一个这样的调用这个我想testing的类…

 public class Caller { private readonly ISomeInterface someInterface; public Caller(ISomeInterface someInterface) { this.someInterface = someInterface; } public void Main() { someInterface.AnotherMethod(); } } 

和一个testing,我想嘲笑接口,并validation扩展方法的调用…

  [Test] public void Main_BasicCall_CallsAnotherMethod() { // Arrange var someInterfaceMock = new Mock<ISomeInterface>(); someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable(); var caller = new Caller(someInterfaceMock.Object); // Act caller.Main(); // Assert someInterfaceMock.Verify(); } 

运行这个testing但是会产生一个exception

 System.ArgumentException: Invalid setup on a non-member method: x => x.AnotherMethod() 

我的问题是,有没有一种很好的方式来模拟混音?

你不能“嘲笑”静态方法(因此扩展方法)与嘲笑框架。 您可以尝试使用Moles( http://research.microsoft.com/en-us/projects/pex/downloads.aspx ),它是Microsoft提供的一种免费工具,它实现了一种不同的方法。 这里是工具的描述:

Moles是基于代表的.NET中testing存根和绕行的轻量级框架。

痣可以用来绕开任何.NET方法,包括密封types的非虚拟/静态方法。

你可以使用任何testing框架(这是独立的)。

我已经使用包装来解决这个问题。 创build一个包装对象并传递你的模拟方法。

参见Paul Irwin的“ 嘲弄unit testing的静态方法” ,它有很好的例子。

我发现我不得不发现扩展方法的内部,我试图嘲笑input,并模拟扩展内部发生了什么。

我认为扩展是静态的,就像直接把代码放在你的方法中一样,所以你需要模拟扩展内部而不是扩展本身。

当我包装对象本身时,我喜欢使用包装器(适配器模式)。 我不知道我会用它来包装扩展方法,这不是对象的一部分。

我使用了Action,Func,Predicate或delegatetypes的内部惰性注入属性,并允许在unit testing期间注入(交换)方法。

  internal Func<IMyObject, string, object> DoWorkMethod { [ExcludeFromCodeCoverage] get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); } set { _DoWorkMethod = value; } } private Func<IMyObject, string, object> _DoWorkMethod; 

然后你调用Func而不是实际的方法。

  public object SomeFunction() { var val = "doesn't matter for this example"; return DoWorkMethod.Invoke(MyObjectProperty, val); } 

有关更完整的示例,请查看http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/