【发布时间】:2018-02-18 18:51:39
【问题描述】:
我正在使用 F# 类型定义来防止我的函数之间的硬依赖,例如
type IType1 = int -> int
type IType2 = int-> string
let func1 (i : int) : int = i * i
let func2 (i : int) : string = i |> string
let higherFunc (dep1 : IType1) (dep2 : IType2) (input : int) : string =
input |> dep1 |> dep2
let curriedFunc = higherFunc func1 func2
let x = curriedFunc 2
输出 x : "4"
显然,这是相当做作和简单的,但想象一下依赖项是解析器和排序器或其他任何东西。我正在编写的更小粒度的功能。
我正在尝试使用 Foq 来帮助我的单元测试装置。这是我正确使用 F# 的第一周,我很难弄清楚如何配置这些类型的模拟。
有两点值得一提:
1 - 如果我使用抽象类,我可以让它工作,但我不想这样做,因为它对于完全相同的最终结果要麻烦得多。例如
type IType1 =
abstract member doSomething : int -> int
type func1 () =
interface IType1 with
member this.doSomething (i: int) = i * i
允许我设置一个类似的模拟
let mT1= Mock.With (fun (x : IType1) -> <@ x.doSomething(any()) --> 5 @>)
但我真的不想这样做。
2 - 如果我只是使用
type IType1 = int -> int
let mT1 = Mock.Of<IType1>()
然后我会返回一个有效值,但如果我尝试以任何方式配置它
let mT1= Mock<IType1>.With (fun x -> <@ x(any()) --> 5 @>)
或
let mT1= Mock<IType1>.With (fun x -> <@ any() --> 5@>)
然后我得到一个例外
System.NotSupportedException : Expected standard function application: Call
或
System.NotSupportedException : Expected standard function application: ValueWithName
我希望我只是在语法上很愚蠢,并且可以做我想做的事。我已经尝试了我能想到的所有变体,包括 .Setup(conditions).Create() 的变体,但我在源代码中找不到任何示例。
我显然可以轻松地制作自己的模拟
let mT1 (i : int) : int = 5
因为任何适合该 int -> int 签名的东西都是有效的,但是如果我想检查该函数是否为 i 传递了某个值,我必须放入一个日志记录步骤等。它只是很高兴让 Foq 来做一些繁重的工作。
编辑 我刚刚注意到根 Mock 对象的签名中有“需要引用类型”(即 Mock )——这是否意味着我没有机会模拟值?如果我不配置 mock,它如何管理它?
【问题讨论】:
-
我应该说我知道我不需要注释所有类型(也不需要在我的代码中),为了清楚起见,我只是在这里做了
-
我在 Foq 存储库中创建了一个问题,地址为 github.com/fsprojects/Foq/issues/34
标签: .net unit-testing f# mocking foq