F#中验证Mock ILogger调用报错,如何修正语法解决问题?
问题
我正在对一个调用ILogger.LogInformation的F#函数进行单元测试,尝试验证该函数是否按预期调用了日志方法。当前使用的Verify语句如下:
let mockLogger = Mock<ILogger<MyFunction>>() // call function that uses ILogger.LogInformation. mockLogger.Verify(fun x -> x.Log( LogLevel.Information, It.IsAny<EventId>(), It.IsAny(), It.IsAny<Exception>(), It.IsAny<Func<It.IsAnyType, Exception, string>>()), Times.Once)
运行时抛出如下错误:
System.ArgumentException: Expression of type 'System.Void' cannot be used for constructor parameter of type 'Microsoft.FSharp.Core.Unit' (Parameter 'a... System.ArgumentException Expression of type 'System.Void' cannot be used for constructor parameter of type 'Microsoft.FSharp.Core.Unit' (Parameter 'arguments[0]') at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index) at System.Dynamic.Utils.ExpressionUtils.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments, String methodParamName) at System.Linq.Expressions.Expression.New(ConstructorInfo constructor, IEnumerable`1 arguments) at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 616 at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 599 at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToLambdaExpression[T](FSharpExpr`1 e) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 698
该异常在调用Verify方法时抛出,请问如何修改代码以解决此错误?
解决方案
这个错误源于F#与C#在无返回值方法的表达式转换逻辑差异:Moq的Verify期望的表达式返回类型和F#的unit类型兼容存在问题。只需在Lambda表达式中明确标记返回unit即可修复,有两种常用方式:
方式一:使用ignore处理返回值
mockLogger.Verify(fun x -> x.Log( LogLevel.Information, It.IsAny<EventId>(), It.IsAny(), It.IsAny<Exception>(), It.IsAny<Func<It.IsAnyType, Exception, string>>()) |> ignore, Times.Once)
方式二:显式返回()
mockLogger.Verify(fun x -> x.Log( LogLevel.Information, It.IsAny<EventId>(), It.IsAny(), It.IsAny<Exception>(), It.IsAny<Func<It.IsAnyType, Exception, string>>()); (), Times.Once)
原理说明:ILogger.Log是返回void的方法,在F#中调用后实际返回unit,但Moq的表达式转换逻辑需要明确的unit标记。通过ignore或显式返回(),可以让F#生成符合Moq要求的表达式,避免类型转换异常。
内容的提问来源于stack exchange,提问作者Matthew MacFarland
相关产品推荐
相关产品推荐

