如何对被测课程引发的事件进行单元测试?

kud*_*ger 1 c# unit-testing

我下面有一节课,负责根据一些商业状况提出活动。

public class EventRaiserClass : IEventRaiserClass 
{
    public event EventHandler SendEventToClient;

    public void RaiseEventForClient()
    {
        SendEventToClient?.Invoke(this, EventArgs.Empty);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的客户班

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
    }
}
Run Code Online (Sandbox Code Playgroud)

EventRaiserClass 被注入到下面的类中,该类负责处理一些订单

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

    public void Process(JObject json)
    {
        _evntRaiser.RaiseEventForClient(); 
    }
}
Run Code Online (Sandbox Code Playgroud)

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

can*_*on7 7

据我所知,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);
Run Code Online (Sandbox Code Playgroud)

您可以走得更远,并测试事件是否恰好引发了一次:

// 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);
Run Code Online (Sandbox Code Playgroud)

如果您不想依赖EventRaiserClass并且使用的是模拟框架,则可以执行以下操作(在此示例中,我使用的是Moq):

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

// Act
processRequest.Process(someJObject);

// Assert
eventRaiser.Verify(x => x.RaiseEventForClient());
Run Code Online (Sandbox Code Playgroud)

同样使用NSubstitute

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

// Act
processRequest.Process(someJObject);

// Assert
eventRaiser.Received().RaiseEventForClient();
Run Code Online (Sandbox Code Playgroud)

作为单独的注释,请考虑一下如何命名课程。大多数编码标准都说,类应使用名词名词短语来命名,而不应以“类”结尾。

所以Client是确定的,但EventRaiserClass有端Class。考虑类似的东西EventRaiser

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