简体   繁体   English

测试与foq的接口

[英]Testing interfaces with foq

I am trying to use Foq to testing an interface with Foq. 我正在尝试使用Foq来测试与Foq的接口。

So far, all examples I have seen for this have been relatively simple, such as the following: 到目前为止,我所看到的所有示例都相对简单,如下所示:

let users = [|{ID = 1; pass = true};{ID = 2; pass= false}|]

type IFoo = 
    abstract member Bar: int -> bool

//tests with Foq
let dataAccess = 
    Mock<IFoo>()
    .Setup(fun x-> <@ x.Bar(users.[0].ID)  @>).Returns(users.[0].pass)
    .Setup(fun x-> <@ x.Bar(users.[1].ID)  @>).Returns(users.[1].pass)
    .Create()

The examples have been sourced from 'Testing with F# - Mikael Lundin' 这些例子来自'用F#测试 - Mikael Lundin'

I have also researched this through a bit of googling (this link was helpful - http://trelford.com/blog/post/Foq.aspx ) 我也通过一些谷歌搜索研究了这个(这个链接很有用 - http://trelford.com/blog/post/Foq.aspx

However, the real Interfaces I want to test are the following: 但是,我要测试的真实接口如下:

type IParameters =
    abstract member ParameterDate : int->string->DateTime 

type IDataSource =
    abstract member MortParameters: IParameters

I have tried a number of different ways to test these (eg defining a function with a signature of int->string to be used as the input to the setup. Alternatively, having the return value as a string->DateTime and the Setup as just an integer. 我已经尝试了许多不同的方法来测试这些(例如,使用int-> string的签名定义一个函数作为设置的输入。或者,将返回值作为字符串 - > DateTime并将Setup设置为只是一个整数。

My question is really the following: When testing interfaces using Foq, how can I extend the testing to interfaces with function signatures of any general length (eg a->b->c->d->e etc.) 我的问题实际上如下:当使用Foq测试接口时,如何将测试扩展到具有任何常规长度的功能签名的接口(例如a-> b-> c-> d-> e等)

Since ParameterDate a property with a function type, you could just set it up as a property that returns a lambda value. 由于ParameterDate是一个具有函数类型的属性,因此您可以将其设置为返回lambda值的属性。 See an example of property set-up in Foq . 请参阅Foq中属性设置示例 This should be easy to modify for your case: 这应该很容易修改为您的情况:

let instance =
    Mock<System.Collections.IList>()
        .Setup(fun x -> <@ x.Count @>).Returns(1)
        .Create()

However, I guess you would lose the ability to have a strict mock with fixed expectations on the function inputs. 但是,我猜你会失去对函数输入进行严格模拟和固定期望的能力。


To enforce only expected inputs for the function returned by the mock property you could provide a function like this: 要仅对mock属性返回的函数强制执行预期输入,您可以提供如下函数:

fun i s ->
    match i, s with
    | 1, "" -> DateTime.Now
    | _ -> failwith "Invalid mock input"

I would probably stop here, but if you're working with code where you need to verify a function was called, as opposed to just ensuring you get the correct output, you could add a helper like this: 我可能会在这里停下来,但是如果你正在使用需要验证函数被调用的代码,而不是只是确保你得到正确的输出,你可以添加一个这样的帮助:

type Verifiable<'a, 'b> (f : 'a -> 'b) =
    let called = ref false
    member this.Func x =
        called := true
        f x
    member this.Verify() =
        if not called.Value then failwith "Mock function was not called"

And here's how you would use it: 以下是您将如何使用它:

let parameterDateMock =
    fun i s ->
        match i, s with
        | 1, "" -> DateTime.Now
        | _ -> failwith "Unexpected mock input"
    |> Verifiable

let parameters =
    { new IParameters with member this.ParameterDate i s = parameterDateMock.Func i s }

parameters.ParameterDate 1 ""

parameterDateMock.Verify()

Caveat: This only verifies the function was called with at least one parameter. 警告:这只验证使用至少一个参数调用函数。 It may have returned another function by currying and not actually run the code in the mock function body. 它可能通过currying返回另一个函数,而不是实际运行mock函数体中的代码。 To get around that you'd need a variation of the Verifiable class for every function arity and use the right one in each case. 为了解决这个问题,你需要为每个函数arity更改Verifiable类,并在每种情况下使用正确的类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM