如果我试图嘲弄包含async
方法的类型,如:异步方法返回null
interface Foo
{
Task<int> Bar();
}
然后模拟的Bar
方法返回null。我想Moq选择default(Task<int>)
作为我的方法的默认返回值,这实际上是null
。然而Moq应该选择诸如Task.FromResult(default(int))
之类的东西作为默认值。我可以强制Moq使异步方法返回非null任务吗?
如果我试图嘲弄包含async
方法的类型,如:异步方法返回null
interface Foo
{
Task<int> Bar();
}
然后模拟的Bar
方法返回null。我想Moq选择default(Task<int>)
作为我的方法的默认返回值,这实际上是null
。然而Moq应该选择诸如Task.FromResult(default(int))
之类的东西作为默认值。我可以强制Moq使异步方法返回非null任务吗?
如果有人有兴趣,我做了一个扩展类,这使得异步方法stubing更简洁:
public static class SetupExtensions
{
public static IReturnsResult<TMock> ReturnsTask<TMock, TResult>(
this ISetup<TMock, Task<TResult>> setup) where TMock : class
{
return setup.Returns(() => Task.FromResult(default(TResult)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, TResult>(
this ISetup<TMock, Task<TResult>> setup, TResult value) where TMock : class
{
return setup.Returns(() => Task.FromResult(value));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, TResult>(
this ISetup<TMock, Task<TResult>> setup, Func<TResult> func) where TMock : class
{
return setup.Returns(Task.Factory.StartNew(func));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, T, TResult>(
this ISetup<TMock, Task<TResult>> setup, Func<T, TResult> func) where TMock : class
{
return setup.Returns<T>(arg => Task.Factory.StartNew(() => func(arg)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, TResult>(
this ISetup<TMock, Task<TResult>> setup, Func<T1, T2, TResult> func) where TMock : class
{
return setup.Returns<T1, T2>((arg1, arg2) => Task.Factory.StartNew(() => func(arg1, arg2)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, T3, TResult>(
this ISetup<TMock, Task<TResult>> setup, Func<T1, T2, T3, TResult> func) where TMock : class
{
return setup.Returns<T1, T2, T3>((arg1, arg2, arg3) => Task.Factory.StartNew(() => func(arg1, arg2, arg3)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, T3, T4, TResult>(
this ISetup<TMock, Task<TResult>> setup, Func<T1, T2, T3, T4, TResult> func) where TMock : class
{
return setup.Returns<T1, T2, T3, T4>((arg1, arg2, arg3, arg4) => Task.Factory.StartNew(() => func(arg1, arg2, arg3, arg4)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock>(this ISetup<TMock, Task> setup, Action action) where TMock : class
{
return setup.Returns(Task.Factory.StartNew(action));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, T>(this ISetup<TMock, Task> setup, Action<T> action) where TMock : class
{
return setup.Returns<T>(arg => Task.Factory.StartNew(() => action(arg)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2>(this ISetup<TMock, Task> setup, Action<T1, T2> action) where TMock : class
{
return setup.Returns<T1, T2>((arg1, arg2) => Task.Factory.StartNew(() => action(arg1, arg2)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, T3>(this ISetup<TMock, Task> setup, Action<T1, T2, T3> action) where TMock : class
{
return setup.Returns<T1, T2, T3>((arg1, arg2, arg3) => Task.Factory.StartNew(() => action(arg1, arg2, arg3)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock, T1, T2, T3, T4>(this ISetup<TMock, Task> setup, Action<T1, T2, T3, T4> action) where TMock : class
{
return setup.Returns<T1, T2, T3, T4>((arg1, arg2, arg3, arg4) => Task.Factory.StartNew(() => action(arg1, arg2, arg3, arg4)));
}
public static IReturnsResult<TMock> ReturnsTask<TMock>(this ISetup<TMock, Task> setup) where TMock : class
{
return setup.Returns(Task.Factory.StartNew(delegate { }));
}
}
一些例子:
//Example 1 :
public interface IFoo
{
Task Bar();
}
var mock = new Mock<IFoo>();
mock.Setup(m => m.Bar()).ReturnsTask(); //await Bar() will return void
//Example 2 :
public interface IFoo
{
Task<int> Bar();
}
var mock = new Mock<IFoo>();
mock.Setup(m => m.Bar()).ReturnsTask(); //await Bar() will return default(int)
//Example 3 :
public interface IFoo
{
Task<int> Bar();
}
var mock = new Mock<IFoo>();
mock.Setup(m => m.Bar()).ReturnsTask(4); //await Bar() will return 4;
//Example 4 :
public interface IFoo
{
Task<int> Bar(int x, int y);
}
var mock = new Mock<IFoo>();
mock.Setup(m => m.Bar(It.IsAny<int>(), It.IsAny<int>()))
.ReturnsTask<IFoo, int, int, int>((x,y) => x + y); //await Bar(x, y) will return x + y;
你只需要存根的杆法,并使其返回Task.FromResult(default(int))
回想一下,起订量框架是开源的。在代码库(可用的here)中,我们可以看到,执行尚未设置的方法调用时,返回值是MethodCallReturn<TMock, TResult>
类中的valueDel
专用字段的结果。那场被实例化,以便它返回的结果类型的默认值:
private Delegate valueDel = (Func<TResult>)(() => default(TResult));
您可以添加将会覆盖正从一个模拟返回给定类型的默认值的方法,或者明确地回报你在Task
的情况下建议使用默认值。
您也可以在Moq issues list page上提出问题。按照aquaraga的建议,如果不处理Moq源代码,那么只需要将Foo
接口存根即可。嘲笑和存根之间差异的快速解释可以在here找到。
貌似这个问题是起订量4.2 fixed。所以你只需要升级到最新版本的Moq(至少它开始返回非空任务在我的情况)
史诗般有用。谢谢:-) – 2013-08-01 14:44:04
这工作出色 – Ian1971 2013-10-10 14:55:02