如何在Moq中设置带异步函数参数的IRunner.Run泛型方法?
问题分析与解决方案
你的问题核心在于泛型方法的类型参数无法被编译器推断,同时代码里还存在语法细节错误,以下是具体解决思路和代码示例:
问题根源
IRunner.Run<T>是泛型方法,你在Setup时使用了未声明的T,编译器无法确定它的具体类型;It.IsAny<ILogger>和It.IsAny<ExecutionContext>缺少调用括号,正确写法应为It.IsAny<ILogger>()(这是方法调用,不是类型引用);- 你传入的异步lambda,实际返回值是
Task(无返回值场景)或Task<TResult>(有返回值场景),这才是Run<T>中T的真实类型。
具体解决代码
场景1:异步lambda无返回值(对应Task类型)
var mockRunner = new Mock<IRunner>(); // 显式指定T为Task,匹配无返回值的异步委托 mockRunner.Setup( x => x.Run<Task>( It.IsAny<ILogger>(), It.IsAny<ExecutionContext>(), It.IsAny<Func<FunctionContext, Task>>() )); // 若需要让mock执行传入的委托,可添加Returns逻辑 mockRunner.Setup( x => x.Run<Task>( It.IsAny<ILogger>(), It.IsAny<ExecutionContext>(), It.IsAny<Func<FunctionContext, Task>>() )).Returns((ILogger log, ExecutionContext ctx, Func<FunctionContext, Task> func) => func(new FunctionContext()) // 传入模拟的FunctionContext并执行委托 );
场景2:异步lambda有返回值(对应Task<TResult>类型)
假设你的调用代码是:
var result = await myRunner.Run(myLog, myContext, async ctx => { return await _fetchData(myContext, trxData); });
对应的mock代码需显式指定T为Task<DataModel>(替换成你的实际返回类型):
var mockRunner = new Mock<IRunner>(); mockRunner.Setup( x => x.Run<Task<DataModel>>( It.IsAny<ILogger>(), It.IsAny<ExecutionContext>(), It.IsAny<Func<FunctionContext, Task<DataModel>>>() )).ReturnsAsync(new DataModel()); // 返回模拟的结果
通用方案(支持任意泛型类型)
如果需要mock能匹配多种T类型的Run调用,可以封装泛型Setup方法:
public static void SetupRunner<T>(Mock<IRunner> mock) { mock.Setup(x => x.Run<T>( It.IsAny<ILogger>(), It.IsAny<ExecutionContext>(), It.IsAny<Func<FunctionContext, T>>() )).Returns(default(T)); } // 使用示例 var mockRunner = new Mock<IRunner>(); SetupRunner<Task>(mockRunner); // 处理无返回值异步调用 SetupRunner<Task<DataModel>>(mockRunner); // 处理有返回值异步调用
内容的提问来源于stack exchange,提问作者Reinsbrain
相关产品推荐
相关产品推荐

