F#Moq返回“在静态成员上的无效设置”

时间:2019-05-28 21:34:17

标签: f# moq

在存储库界面文件中

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

注意。我不想将方法更改为  这个:
abstract member Find: email:string * firstname:string * lastname:string

注释2 [已添加]
我不想这样使用 Object Expression

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个其他提供程序可以注入...而且我认为这种情况下根本不干净。

那是什么错误?
任何想法如何模拟该方法?


[更新]
我将Moq从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

它有效。

1 个答案:

答案 0 :(得分:2)

我不希望有一种方法可以使它与Moq一起使用。 Moq库假定代码遵循常规的C#编码实践,而F#以咖喱形式编译具有多个参数的方法的方式只是C#从未定义过。

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

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

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

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

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

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

一个不知道此事的工具无法确定这实际上意味着用三个参数调用Find

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