我使用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#的第一周,我很难想出如何配置这些类型的模拟。
值得一提的有两件事:
如果我使用抽象类,我可以让它工作,但我不想这样做,因为对于完全相同的最终结果来说,麻烦要大得多。例如
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(条件).Create()的变体,而且我在源代码中找不到任何例子。
很明显,我可以很容易地做出自己的模仿,比如
let mT1 (i : int) : int = 5由于任何适合于int -> int签名的内容都是有效的,但是如果我想检查函数是否为i传递了某个值,则必须输入一个日志步骤等等。有福克来做一些繁重的工作就太好了。
编辑我刚刚注意到根mock对象的签名中有“requires type”(即Mock <‘TAbstract(需要引用类型)>)--这是否意味着我没有机会模拟值?如果我不配置模拟值,它怎么会管理它呢?
发布于 2018-02-17 15:27:43
你没必要嘲笑。如果依赖项只是函数类型,则只需提供函数:
let mT1= fun x -> 5对象嘲弄的整个概念是由面向对象的人发明的,以弥补对象不能很好地组成的事实(或者根本就不是这样)。当整个系统正常运行时,您可以当场创建函数。没必要嘲笑我。
如果您真的很难使用Foq的工具,比如日志记录和验证(我敦促您重新考虑:您的测试会更容易、更有弹性),您可以始终让自己成为功能的代理主机:
type ISurrogate<'t, 'r> =
abstract member f: 't -> 'r
// Setup
let mT1 = Mock.Create<ISurrogate<int, int>>()
mT1.Setup(...)...
let mT2 = Mock.Create<ISurrogate<int, string>>()
mT2.Setup...
higherFunc mT1.f mT2.f 42
mT1.Received(1).Call( ... ) // Verification这样,丑陋就局限于您的测试,并且不会使您的生产代码复杂化。
显然,这只适用于单参数函数。对于带有多个临时参数的函数,您必须对参数进行元组化,并将调用包装在注入站点的lambda中:
// Setup
let mT1 = Mock.Create<ISurrogate<int * int, int>>()
higherFunc (fun x y -> mT1.f(x, y)) ...如果您发现这种情况经常发生,您可以打包lambda创建以供重用:
let inject (s: ISurrogate<_,_>) x y = s.f (x,y)
higherFunc (inject mT1) ...https://stackoverflow.com/questions/48842609
复制相似问题