在 VB.NET 中使用 NSubstitute 发起一个事件

Raising an event with NSubstitute in VB.NET

我在使用 VB.NET 和 NSubstitute 的单元测试中引发事件时遇到问题。被模拟的接口定义了一个事件:

Event BlockOfVehiclesProcessed(source As Object, stats As ProcessingStats)

正在测试的 class 为事件注册了一个处理程序。在单元测试中,我想引发事件,以便调用被测 class 中的处理程序。基于 NSubstitute 文档(不幸的是,所有 C#)和 Whosebug 等的各种答案,我尝试了各种排列:

AddHandler mock.BlockOfVehiclesProcessed, Raise.EventWith(New ProcessingStats(50))

但我还没有找到任何可以编译的东西。一条错误消息:

Value of type 'EventHandlerWrapper(...)' cannot be converted to '...BlockOfVehiclesProcessedEventHandler'

我尝试将 0 个参数和 2 个参数传递给 EventWith(),我尝试为 EventWith() 明确指定类型参数,我尝试了 Raise.Event(),但我找不到神奇的序列让编译器开心。有没有人有引发事件的有效 VB 单元测试示例?

然后问题是 NSubstitute 不支持在没有明确提供事件处理程序类型的情况下声明事件时由 vb.net 创建的匿名事件处理程序类型。

如果必须使用 NSubstitute(并作为问题的答案),声明明确提供的事件处理程序类型的事件将解决您的问题。

' Example with Action as event handler type
Public Interface IVehicleProcessor
    Event BlockOfVehiclesProcessed As Action(Of Object, String) 
End Interface

Public Class System
    Private ReadOnly _processor As IVehicleProcessor
    Public Property ProcessedStats As String

    Public Sub New(IVehicleProcessor processor)
        _processor = processor
        AddHandler _processor.BlockOfVehiclesProcessed, Sub(sender, stats) ProcessedStats = stats
    End Sub
End System

' Test
Public Sub ShouldNotifyProcessedStats()
    Dim fakeProcessor = Substitute.For(Of IVehicleProcessor)
    Dim system As New System(fakeProcessor)

    ' Raise an event with known event handler type
    AddHandler fakeProcessor.BlockOfVehiclesProcessed, 
        Raise.Event(Of Action(Of Object, String))(fakeProcessor, "test-stats")

    system.ProcessedStats.Should().Be("test-stats") ' Pass
End Sub

另一种方法是使用事件创建自己的假接口实现。我发现这种方法要好得多,只是因为您不需要更改生产代码,因为某些测试框架无法支持 vb.net 语言功能。

Public Class FakeVehicleProcessor
    Implements IVehicleProcessor

    Public Event BlockOfVehiclesProcessed(source As Object, stats As String) Implements IVehicleProcessor.BlockOfVehiclesProcessed

    ' Use this method to raise an event with required arguments
    Public Sub RaiseEventWith(stats As String)
        RaiseEvent BlockOfVehiclesProcessed(Me, stats)
    End Sub
End Class

' Test
Public Sub ShouldNotifyProcessedStats()
    Dim fakeProcessor As New FakeVehicleProcessor()
    Dim system As New System(fakeProcessor)

    fakeProcessor.RaiseEventWith("test-stats")

    system.ProcessedStats.Should().Be("test-stats") ' Pass
End Sub