F# 起订量返回 "Invalid setup on a static member"

标签 f# moq

在存储库接口(interface)文件中

type public IAccountRepository =
    abstract member Find: email:string -> firstname:string -> lastname:string -> Account

在测试文件中

open Moq
let mutable accountRepository = Mock<IAccountRepository>(MockBehavior.Strict)
accountRepository.Setup( fun rep -> rep.Find "aaa" "bbb" "ccc" ).Returns(account) |> ignore

accountRepository.Setup 在运行时引发此错误:

System.NotSupportedException:静态成员上的设置无效:rep => FSharpFunc.InvokeFast (FuncConvert.ToFSharpFunc

注意。我不想改变我的方法 这个:
抽象成员查找:电子邮件:字符串 * 名字:字符串 * 姓氏:字符串

注释2[已添加]
我不想使用像这样的对象表达式:

let accountRepository_2 = {
    new IAccountRepository with
        member __.Find a b c = account   // <--- this is the only mock I need
        member __.Create x = ()
        member __.Delete x = ()
        member __.FindByMobile x = account
        member __.FindByWallet x y = account
        member __.Read x = account
    }

这不是一个可行的解决方案:我有 3 个存储库和 2 个其他提供程序需要注入(inject)...而且我认为对于这种情况来说根本不干净。

这个错误是什么?
知道如何模拟该方法吗?


[更新]
我将起订量从 4.10.1 更新到 4.11.0。错误已更改:

System.NotSupportedException : Unsupported expression: ... => 
FSharpFunc<string, string>.InvokeFast<string, Account>(...

我正在使用NSubstitute:

let accountRepository = Substitute.For<IAccountRepository>()
(accountRepository.Find "aaa" "bbb" "ccc").Returns(account) |> ignore

并且它有效。

最佳答案

我没想到有办法让它与 Moq 一起使用。 Moq 库假设代码遵循通常的 C# 编码实践,并且 F# 以柯里化(Currying)形式编译具有多个参数的方法的方式并不是 C# 定义它的方式。

当您在 F# 中编写以下内容时:

accountRepository.Setup(fun rep -> 
  rep.Find "aaa" "bbb" "ccc")

Moq 实际上看到的东西看起来更像是:

accountRepository.Setup(fun rep -> 
  rep.Find("aaa").Invoke("bbb").Invoke("ccc"))

实际上,情况比这更糟糕,因为当编译器可以静态确定参数数量时,F# 会进行优化,并将一些调用折叠为 InvokeFast 调用:

accountRepository.Setup(fun rep -> 
  rep.Find("aaa").InvokeFast("bbb", "ccc"))

不了解这一点的工具无法弄清楚这实际上意味着使用三个参数调用 Find

我认为最好的选择是更改方法签名(尽管您明确表示您不想这样做)。或者,您可以添加一个轻量级包装器用于测试目的。另一种选择是尝试 F# 模拟库 Foq看看是否能更好地处理这种情况。

关于F# 起订量返回 "Invalid setup on a static member",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56350320/

相关文章:

bash - 如何强制 F# interactive 默认引用 Gtk#?

c# - 我如何模拟 FromSql() 方法?

c# - 如何验证在最小起订量中未调用该方法?

f# - 比较列表中子列表的长度 F#

c# - 如何从 .NET MVC Controller 测试 JsonResult

c# - 如何将 Predicate<T> 转换为 Expression<Predicate<T>> 以与 Moq 一起使用?

c# - 模拟数据访问器

c# - 即使 Process.HasExited 为真,Process.WaitForExit 也不会返回

F# 尝试处理未处理的异常

f# - 哪个与缩进规则的匹配在这里起作用?