C# 在不指定所有输入参数类型的情况下获取方法引用
我想用Moq快速模拟一些方法调用。我确实有一些冗长的方法签名,具有很长的参数类型名称,尽管我很懒,但当方法设置为无论如何都失败时,不管输入参数的数量如何,我不想为所有签名键入C# 在不指定所有输入参数类型的情况下获取方法引用,c#,generics,moq,C#,Generics,Moq,我想用Moq快速模拟一些方法调用。我确实有一些冗长的方法签名,具有很长的参数类型名称,尽管我很懒,但当方法设置为无论如何都失败时,不管输入参数的数量如何,我不想为所有签名键入It.IsAny()。 更具体地说,我提出了这个扩展方法,但是示例调用中没有绑定T1(第一个参数): public static void SetResult<T,T1,TResult>(this Mock<T> mock, Func<T, Func<T1, TResult>>
It.IsAny()
。更具体地说,我提出了这个扩展方法,但是示例调用中没有绑定
T1
(第一个参数):
public static void SetResult<T,T1,TResult>(this Mock<T> mock, Func<T, Func<T1, TResult>> method, TResult result, Func<T1> filterT1 = null)
where T : class
{
if(filterT1 == null)
{
filterT1 = It.IsAny<T1>;
}
mock.Setup(m => method.Invoke(m).Invoke(filterT1.Invoke()))
.Returns(result);
}
// I want to use this like the following
Mock<Foo> mock = /* ... */;
mock.SetResult(foo => foo.bar, "Some return value"); // Doesn't work
mock.SetResult<Foo, int, string>(foo => foo.bar, "Some return value"); // Works
mock.SetResult(foo => foo.bar, "Some return value", () => 42); // Works too
设置
需要一个表达式
(注意条
-输入类型缺少类型定义),并检查该表达式以模拟调用。任何It.*
-只能在此表达式中进行调用(请参阅为什么使用*.invoke()
)
endresult不仅是设置结果的方法,还包括异常、序列等但我可以自己解决这个问题。这可能需要一点改进,但它似乎与您所说的接近。唯一的区别是,它当前需要一个
MethodInfo
而不是Func
来获得它应该模拟的方法
它迭代所有参数,并使用System.Linq.Expression
为每个参数创建IsAny
表达式
public static class MoqExtension
{
public static void SetResult<T, TResult>(this Mock<T> mock, MethodInfo methodInfo, TResult result)
where T : class
{
var expressions = new List<Expression>();
// Create IsAny for each parameter
foreach (var parameter in methodInfo.GetParameters())
{
var pType = parameter.ParameterType;
var isAnyMethod = typeof(It).GetMethods((BindingFlags)(-1))
.Where(x => x.Name == "IsAny")
.First();
var genericIsAnyMethod = isAnyMethod.MakeGenericMethod(pType);
var isAnyExp = Expression.Call(genericIsAnyMethod);
expressions.Add(isAnyExp);
}
// Create method call
var argParam = Expression.Parameter(typeof(T), "x");
var callExp = Expression.Call(argParam, methodInfo, expressions.ToArray());
var lambda = Expression.Lambda<Func<T, TResult>>(callExp, argParam);
// invoke setup method
var mockType = mock.GetType();
var setupMethod = mockType.GetMethods()
.Where(x => x.Name == "Setup" && x.IsGenericMethod)
.First();
var genericMethod = setupMethod.MakeGenericMethod(typeof(TResult));
var res = genericMethod.Invoke(mock, new object[] { lambda }) as ISetup<T, TResult>;
res.Returns(result);
}
}
公共静态类MoqExtension
{
公共静态void SetResult(此模拟模拟、MethodInfo MethodInfo、TResult结果)
T:在哪里上课
{
var表达式=新列表();
//为每个参数创建IsAny
foreach(methodInfo.GetParameters()中的var参数)
{
var pType=parameter.ParameterType;
var isAnyMethod=typeof(It).GetMethods((BindingFlags)(-1))
.Where(x=>x.Name==“IsAny”)
.First();
var genericanyMethod=isAnyMethod.MakeGenericMethod(pType);
var isAnyExp=Expression.Call(GenericsAnyMethod);
expressions.Add(isAnyExp);
}
//创建方法调用
var argParam=表达式参数(typeof(T),“x”);
var callExp=Expression.Call(argParam,methodInfo,expressions.ToArray());
var lambda=Expression.lambda(callExp,argParam);
//调用设置方法
var mockType=mock.GetType();
var setupMethod=mockType.GetMethods()
.Where(x=>x.Name==“Setup”&&x.IsGenericMethod)
.First();
var genericMethod=setupMethod.MakeGenericMethod(typeof(TResult));
var res=genericMethod.Invoke(mock,新对象[]{lambda})作为ISetup;
回复(结果);
}
}
用法示例:
[Fact]
public void MoqTestDynamic2()
{
var m = new Mock<ITestInterface>();
m.SetResult(typeof(ITestInterface).GetMethod("GetAnotherInt"), 168);
Assert.Equal(168, m.Object.GetAnotherInt("s", 1, 3));
Assert.Equal(168, m.Object.GetAnotherInt("p", 1, 35));
Assert.Equal(168, m.Object.GetAnotherInt(null, 1, 3));
}
public interface ITestInterface
{
int GetInt(string s);
int GetAnotherInt(string s, int i, long l);
}
[事实]
公共无效MoqTestDynamic2()
{
var m=新的Mock();
m、 SetResult(typeof(ITestInterface).GetMethod(“GetAnotherInt”),168;
Assert.Equal(168,m.Object.GetAnotherInt(“s”,1,3));
Assert.Equal(168,m.Object.GetAnotherInt(“p”,1,35));
Assert.Equal(168,m.Object.GetAnotherInt(null,1,3));
}
公共接口ITestInterface
{
int GetInt(字符串s);
int-GetAnotherInt(字符串s,int-i,长l);
}
一定有更好的方法来解决这个问题
[Fact]
public void MoqTestDynamic2()
{
var m = new Mock<ITestInterface>();
m.SetResult(typeof(ITestInterface).GetMethod("GetAnotherInt"), 168);
Assert.Equal(168, m.Object.GetAnotherInt("s", 1, 3));
Assert.Equal(168, m.Object.GetAnotherInt("p", 1, 35));
Assert.Equal(168, m.Object.GetAnotherInt(null, 1, 3));
}
public interface ITestInterface
{
int GetInt(string s);
int GetAnotherInt(string s, int i, long l);
}