c# - 如何对被测类引发的事件进行单元测试?

标签 c# unit-testing

我有下面的类负责根据某些业务条件引发事件。

public class EventRaiserClass : IEventRaiserClass 
{
    public event EventHandler SendEventToClient;

    public void RaiseEventForClient()
    {
        SendEventToClient?.Invoke(this, EventArgs.Empty);
    }
}

这是我的客户端类

public class Client :IClient
{
    EventRaiserClass _eventRaiser;
    public Client(EventRaiserClass eventraiser)
    {
        _eventRaise = eventraise;
        _iotGwStatus.SendEventToClient += OnSendEventToClient;
    }

    private async void OnSendEventToClient(object sender, EventArgs e)
    {
        await SendEventToClient();
    }

    public async Task SendEventToClient()
    {
        //do some operation
    }
}

EventRaiserClass被注入(inject)到下面负责处理一些订单的类

public class ProcessRequest: IProcessRequest
{
    IEventRaiserClass _evntRaiser;
    public ProcessRequest(IEventRaiserClass evntRaiser)
    {
        _evntRaiser = evntRaiser;
    }

    public void Process(JObject json)
    {
        _evntRaiser.RaiseEventForClient(); 
    }
}

现在,如何对 Process 方法进行单元测试?如何确保在调用 process 方法时引发事件?

最佳答案

据我所知,Client 类与这个问题无关?您只想测试调用 ProcessRequest.Process 调用 EventRaiserClass.RaiseEventForClient

一个简单的方法,没有任何模拟,使用 EventRaiserClass:

var eventRaiser = new EventRaiserClass();
bool eventRaised = false;
eventRaiser.SendEventToClient += (o, e) => eventRaised = true;

var processRequest = new ProcessRequest(eventRaiser);
processRequest.Process(someJObject);

Assert.True(eventRaised);

您可以更进一步,测试事件是否恰好引发一次:

// Arrange
var eventRaiser = new EventRaiserClass();
int eventRaisedCount = 0;
eventRaiser.SendEventToClient += (o, e) => eventRaisedCount++;

var processRequest = new ProcessRequest(eventRaiser);

// Act
processRequest.Process(someJObject);

// Assert
Assert.Equal(1, eventRaisedCount);

如果你不想依赖 EventRaiserClass 并且你正在使用模拟框架,你可以这样做(我在这个例子中使用 Moq):

// Arrange
var eventRaiser = Mock<IEventRaiser>();
var processRequest = new ProcessRequest(eventRaiser.Object);

// Act
processRequest.Process(someJObject);

// Assert
eventRaiser.Verify(x => x.RaiseEventForClient());

同样使用NSubstitute :

// Arrange
var eventRaiser = Substitute.For<IEventRaiser>();
var processRequest = new ProcessRequest(eventRaiser);

// Act
processRequest.Process(someJObject);

// Assert
eventRaiser.Received().RaiseEventForClient();

作为单独的注释,请考虑一下如何命名类。大多数编码标准规定类应该使用名词名词短语 命名,并且不应以“Class”结尾。

所以Client没问题,但是EventRaiserClassClass结尾。考虑像 EventRaiser 这样的东西。

ProcessRequest 不是名词或名词短语——它听起来像一条指令(“处理此请求”),这通常是您命名方法而非类的方式。考虑像 RequestProcessor 这样的东西,它是一个处理请求的对象。

关于c# - 如何对被测类引发的事件进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58482360/

相关文章:

c# - LINQ 表达式。从范围引用的类型变量 'p',但未定义

c# - 如何减小 Crystal 报表工具栏的宽度?

Angular 5 : How to write a Jasmine unit test for a data binding attribute

c - 单元测试错误条件 - EINTR

node.js - Jest/Istanbul 覆盖未加载 require 的模块

c# - 以编程方式设置 WPF 组合框中的选定项目

c# - 使用反射从 C# 对象中去除所有值

rest - 无法使用golang中的gorilla mux从url读取变量

C# - 更高效的三元运算符

Python:如何在我的测试套件中制作临时文件?