在Foq中模拟具有虚拟内部可设置属性的抽象类

时间:2019-03-13 13:35:52

标签: unit-testing f# foq

我已经用F#编写了Azure持久函数,并按照https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-unit-testing的指南尝试编写单元测试。我试图使用Foq创建抽象类DurableOrchestrationContextBase的模拟实例,但是失败并出现以下错误:

  

System.TypeLoadException:类型'Mock.DurableOrchestrationContextBase1953fcc2-be15-41fc-850c-5a5813aace89'中的方法'set_InstanceId'来自程序集'Foq.Dynamic,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null'覆盖该程序集不可见的方法。

与该属性有关的错误:

public virtual string InstanceId { get; internal set; }

进一步的研究表明,Foq能够使用抽象C#类上的内部设置方法模拟非虚拟,非抽象属性,但是如果它们是虚拟的,则无法应对。

有什么方法可以在F#测试中模拟此类?在这种情况下,滚动我自己的实现会很尴尬,因为DurableOrchestrationContextBase是一个很大的类,有许多成员需要实现。

1 个答案:

答案 0 :(得分:0)

最后,我通过切换到NSubstitute来解决此问题,该功能可以模拟此类。 NSubstitute的API在F#中相对易于使用,因为(例如,与Moq不同),您可以配置大多数方案而无需求助于表达式树,尤其是当您可以利用结构相等性来验证参数时。例如:

let returns<'T> (value: 'T) x = x.Returns(value) |> ignore

[<Fact>]
let ``should call my activity``() =
    task {
        // Arrange
        let context = Substitute.For<DurableOrchestrationContextBase>()
        context.GetInput<SomeType>() |> returns { Foo = 42 }

        // Act
        do! runOrchestrator context

        // Assert
        // In C# you would have to do Arg.Is<SomeClass>(x => x.Bar == 43 && x.Baz == "bla")
        do! context.Received().CallActivityAsync("MyActivity", { Bar = 43; Baz = "bla" })
    }