简体   繁体   中英

How do I unit test the event raised by class under test?

I have below class which is responsible for raising the event based on some business conditions.

public class EventRaiserClass : IEventRaiserClass 
{
    public event EventHandler SendEventToClient;

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

Here is my Client class

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 is injected to below class which is responsible for processing some orders

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

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

Now, How do I unit test above Process method? How do I make sure the event is raised when process method is called?

As far as I can tell, the Client class is irrelevant to this question? You just want to test the calling ProcessRequest.Process calls EventRaiserClass.RaiseEventForClient .

A simple way, without any mocks, using the 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);

You can go further, and test that the event is raised exactly once:

// 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);

If you don't want to rely on EventRaiserClass and you're using a mocking framework, you can do something like this (I'm using Moq in this example):

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

// Act
processRequest.Process(someJObject);

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

The same using NSubstitute :

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

// Act
processRequest.Process(someJObject);

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

As a separate note, think a bit about how you name your classes. Most coding standards say that classes should be named using a noun or noun phrase , and shouldn't end with "Class".

So Client is OK, but EventRaiserClass ends with Class . Consider something like EventRaiser .

ProcessRequest isn't a noun or noun phrase -- it sounds like an instruction ("process this request"), which is typically how you'd name a method, not a class. Consider something like RequestProcessor , which is an object which processes requests.

You may also want to check the thrown event with regard to sender and eventArgs . If you don't want to write three test methods to test the entire event raising procedure, then Nuclear.Test is for you.

[TestMethod]
void TestProcessRaisesEvent() {

    // arrange
    var eventRaiser = new EventRaiserClass();
    var processRequest = new ProcessRequest(eventRaiser);
    var json = default(JObject); // create your json
    Action action = () => processRequest.Process(json);

    // act / assert
    Test.If.RaisesEvent(eventRaiser, "SendEventToClient", action, out Object sender, out EventArgs e);
    Test.If.ReferencesEqual(eventRaiser, sender);
    Test.If.ValuesEqual(e, EventArgs.Empty);

}

You should consider testing EventRaiserClass and ProcessRequest separately however.

[TestMethod]
void TestEventRaiserRaisesEvent() {

    // arrange
    var eventRaiser = new EventRaiserClass();
    Action action = () => eventRaiser.RaiseEventForClient();

    // act / assert
    Test.If.RaisesEvent(eventRaiser, "SendEventToClient", action, out Object sender, out EventArgs e);
    Test.If.ReferencesEqual(eventRaiser, sender);
    Test.If.ValuesEqual(e, EventArgs.Empty);

}

[TestMethod]
void TestProcessRaisesEvent() {

    // arrange
    var eventRaiser = new EventRaiserClass();
    var processRequest = new ProcessRequest(eventRaiser);
    var json = default(JObject); // create your json
    Action action = () => processRequest.Process(json);

    // act / assert
    Test.If.RaisesEvent(eventRaiser, "SendEventToClient", action, out Object sender, out EventArgs e);

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM