Moq -是否可以设置一个mock而不使用它



我一直使用Moq进行单元测试。虽然有时我嘲笑有很多参数的方法。

想象一个这样的方法:

public class WorkClient {
public void DoSomething(string itemName, 
int itemCount, 
ServiceClientCredential cred, 
CancellationToken = default(CancellationToken){}
}

当我去设置模拟时,我最终不得不做相当多的It.IsAny<T>()。我通常为每个测试创建一个模拟实例,所以我不关心是否匹配参数。

但是我的mock仍然是这样的

var newMockClient = new Mock<WorkClient>();
newMockClient.Setup(x => x.DoSomething(
It.IsAny<string>(), 
It.IsAny<int>(),
It.IsAny<ServiceClientCredential(),
It.IsAny<CancellationToken>())
.Returns(blah);

如果存在LazySetup,我希望能够简单地使用它,就像这样。

newMockClient.Setup(x=>x.DoSomething()).Returns(blah);

有这样的惰性模式吗?

基于这个要点,你可以为SetupDefaultArgs创建一个重载,它可以很好地与void返回类型一起工作。您需要添加对Moq.Language.FlowSystem.Linq.Expressions;的引用

public static ISetup<T> SetupDefaultArgs<T>(this Mock<T> mock, string methodName)
where T : class
{
var method = typeof(T).GetMethod(methodName);
if (method == null)
throw new ArgumentException($"No method named '{methodName}' exists on type '{typeof(T).Name}'");

var instance = Expression.Parameter(typeof(T), "m");
var callExp = Expression.Call(instance, method, method.GetParameters().Select(p => GenerateItIsAny(p.ParameterType)));
var exp = Expression.Lambda<Action<T>>(callExp, instance);
return mock.Setup(exp);
}
//helper method for above
private static MethodCallExpression GenerateItIsAny(Type T)
{
var ItIsAnyT = typeof(It)
.GetMethod("IsAny")
.MakeGenericMethod(T);
return Expression.Call(ItIsAnyT);
}

所以,在你的例子中,用法看起来像这样:

public interface IWorkClient
{
void DoSomething(string itemName, int itemCount,
ServiceClientCredential cred,
CancellationToken token = default(CancellationToken));
}
var mock = new Mock<IWorkClient>();
mock.SetupDefaultArgs(nameof(IWorkClient.DoSomething));

要确保它已被调用,可以执行以下操作:

//Arrange
var mock = new Mock<IWorkClient>();
mock.SetupDefaultArgs(nameof(IWorkClient.DoSomething))
.Callback(() => Console.WriteLine("DoSomething has been called"));
var cts = new CancellationTokenSource();
//Act       
mock.Object.DoSomething("1", 2, null, cts.Token);
//Assert
mock.Verify(client => client.DoSomething("1", 2, null, cts.Token), Times.Once);

相关内容

最新更新