使用foq测试接口



我正在尝试使用Foq来测试带有Foq的接口。

到目前为止,我看到的所有例子都相对简单,例如:

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()

示例来源于"F#-Mikael Lundin测试"

我也通过谷歌搜索对此进行了研究(这个链接很有帮助-http://trelford.com/blog/post/Foq.aspx)

然而,我想测试的真正接口如下:

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

我尝试了很多不同的方法来测试这些(例如,定义一个签名为int->string的函数,用作设置的输入。或者,将返回值作为string->DateTime,将设置作为整数。

我的问题实际上是:当使用Foq测试接口时,我如何将测试扩展到具有任何通用长度的函数签名的接口(例如a->b->c->d->e等)

由于ParameterDate是一个具有函数类型的属性,您可以将其设置为返回lambda值的属性。请参阅Foq中的属性设置示例。这应该很容易为您的情况修改:

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

然而,我想您将失去对函数输入具有固定期望的严格mock的能力。


为了只强制mock属性返回的函数的预期输入,您可以提供这样的函数:

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

我可能会到此为止,但如果您使用的代码需要验证函数是否被调用,而不是仅仅确保获得正确的输出,那么您可以添加这样的帮助程序:

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"

以下是如何使用它:

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()

注意:这只验证函数是否至少使用了一个参数调用。它可能通过currying返回了另一个函数,而没有实际运行mock函数体中的代码。为了绕过这一点,您需要为每个函数arity提供一个可验证类的变体,并在每种情况下使用正确的类。

最新更新