如果我試圖嘲弄包含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