异步方法返回null

如果我尝试模拟包含async方法的类型,例如:

 interface Foo { Task Bar(); } 

然后mock的Bar方法返回null。 我猜Moq选择default(Task)作为我的方法的默认返回值,这确实是null 。 但是,Moq应该选择像Task.FromResult(default(int))这样的默认值。 我可以强制Moq使异步方法返回非空任务吗?

如果有人感兴趣,我创建了一个扩展类,它使异步方法更简洁:

 public static class SetupExtensions { public static IReturnsResult ReturnsTask( this ISetup> setup) where TMock : class { return setup.Returns(() => Task.FromResult(default(TResult))); } public static IReturnsResult ReturnsTask( this ISetup> setup, TResult value) where TMock : class { return setup.Returns(() => Task.FromResult(value)); } public static IReturnsResult ReturnsTask( this ISetup> setup, Func func) where TMock : class { return setup.Returns(Task.Factory.StartNew(func)); } public static IReturnsResult ReturnsTask( this ISetup> setup, Func func) where TMock : class { return setup.Returns(arg => Task.Factory.StartNew(() => func(arg))); } public static IReturnsResult ReturnsTask( this ISetup> setup, Func func) where TMock : class { return setup.Returns((arg1, arg2) => Task.Factory.StartNew(() => func(arg1, arg2))); } public static IReturnsResult ReturnsTask( this ISetup> setup, Func func) where TMock : class { return setup.Returns((arg1, arg2, arg3) => Task.Factory.StartNew(() => func(arg1, arg2, arg3))); } public static IReturnsResult ReturnsTask( this ISetup> setup, Func func) where TMock : class { return setup.Returns((arg1, arg2, arg3, arg4) => Task.Factory.StartNew(() => func(arg1, arg2, arg3, arg4))); } public static IReturnsResult ReturnsTask(this ISetup setup, Action action) where TMock : class { return setup.Returns(Task.Factory.StartNew(action)); } public static IReturnsResult ReturnsTask(this ISetup setup, Action action) where TMock : class { return setup.Returns(arg => Task.Factory.StartNew(() => action(arg))); } public static IReturnsResult ReturnsTask(this ISetup setup, Action action) where TMock : class { return setup.Returns((arg1, arg2) => Task.Factory.StartNew(() => action(arg1, arg2))); } public static IReturnsResult ReturnsTask(this ISetup setup, Action action) where TMock : class { return setup.Returns((arg1, arg2, arg3) => Task.Factory.StartNew(() => action(arg1, arg2, arg3))); } public static IReturnsResult ReturnsTask(this ISetup setup, Action action) where TMock : class { return setup.Returns((arg1, arg2, arg3, arg4) => Task.Factory.StartNew(() => action(arg1, arg2, arg3, arg4))); } public static IReturnsResult ReturnsTask(this ISetup setup) where TMock : class { return setup.Returns(Task.Factory.StartNew(delegate { })); } } 

一些例子 :

 //Example 1 : public interface IFoo { Task Bar(); } var mock = new Mock(); mock.Setup(m => m.Bar()).ReturnsTask(); //await Bar() will return void //Example 2 : public interface IFoo { Task Bar(); } var mock = new Mock(); mock.Setup(m => m.Bar()).ReturnsTask(); //await Bar() will return default(int) //Example 3 : public interface IFoo { Task Bar(); } var mock = new Mock(); mock.Setup(m => m.Bar()).ReturnsTask(4); //await Bar() will return 4; //Example 4 : public interface IFoo { Task Bar(int x, int y); } var mock = new Mock(); mock.Setup(m => m.Bar(It.IsAny(), It.IsAny())) .ReturnsTask((x,y) => x + y); //await Bar(x, y) will return x + y; 

您将只需要存根Bar方法,并使其返回Task.FromResult(default(int))

看起来这个问题在Moq 4.2中得到修复 。 所以你只需要升级到最新版本的Moq(至少它开始在我的情况下返回非空任务)

回想一下,Moq框架是开源的。 在代码库( 这里可用)中,我们可以看到,当执行尚未设置的方法调用时,返回值是MethodCallReturn类中valueDel私有字段的结果。 该字段被实例化,以便返回结果类型的默认值:

  private Delegate valueDel = (Func)(() => default(TResult)); 

您可以添加一个方法,该方法将覆盖从Mock返回的给定类型的默认值,或者在Task案例中显式返回建议的默认值。

您还可以在Moq问题列表页面上提交问题 。

但是,如果没有处理Moq源代码,那么就像aquaraga建议的那样,你只需要存根Foo接口。 可以在此处找到模拟和存根之间差异的快速解释。