F# 最小起订量 returns "Invalid setup on a static member"
F# Moq returns "Invalid setup on a static member"
在存储库接口文件中
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 个其他提供程序要注入...我认为对于这种情况来说根本不干净。
那个错误是什么?
知道如何模拟该方法吗?
[更新]
我将最小起订量从 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 库假定代码遵循通常的 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"))
实际上,它甚至比这更糟糕,因为 F# 在编译器可以静态确定参数数量时进行了优化,并将一些调用折叠为 InvokeFast
调用:
accountRepository.Setup(fun rep ->
rep.Find("aaa").InvokeFast("bbb", "ccc"))
不知道这一点的工具无法弄清楚这实际上意味着用三个参数调用 Find
。
我认为最好的选择是更改方法签名(尽管您明确表示不想这样做)。或者,您可以添加一个轻量级包装器用于测试目的。另一种选择是尝试 F# 模拟库 Foq 看看它是否能更好地处理这种情况。
在存储库接口文件中
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 个其他提供程序要注入...我认为对于这种情况来说根本不干净。
那个错误是什么?
知道如何模拟该方法吗?
[更新]
我将最小起订量从 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 库假定代码遵循通常的 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"))
实际上,它甚至比这更糟糕,因为 F# 在编译器可以静态确定参数数量时进行了优化,并将一些调用折叠为 InvokeFast
调用:
accountRepository.Setup(fun rep ->
rep.Find("aaa").InvokeFast("bbb", "ccc"))
不知道这一点的工具无法弄清楚这实际上意味着用三个参数调用 Find
。
我认为最好的选择是更改方法签名(尽管您明确表示不想这样做)。或者,您可以添加一个轻量级包装器用于测试目的。另一种选择是尝试 F# 模拟库 Foq 看看它是否能更好地处理这种情况。