kudlatiger
kudlatiger

Reputation: 3278

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?

Upvotes: 1

Views: 339

Answers (2)

MikeLimaSierra
MikeLimaSierra

Reputation: 868

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

}

Upvotes: 1

canton7
canton7

Reputation: 42245

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.

Upvotes: 7

Related Questions