我已经用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
是一个很大的类,有许多成员需要实现。
答案 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" })
}