Unit Testing in C#
  • Unit testing in C#
  • Unit testing
    • What to test
    • When to test
    • Qualities of a good unit test suite
    • Qualities of a good unit test
    • Dealing with dependencies
    • Running the tests
  • NUnit
    • Quick glance at NUnit
    • Creating a NUnit test project
    • Anatomy of a test fixture
    • Lifecycle of a test fixture
    • Assertions
    • Asynchronous executions
    • Parameterized tests
    • Assumptions
    • Describing your tests
  • Moq
    • Quick glance at Moq
    • Method arguments
    • Method calls
    • Properties
    • Results
    • Callbacks
    • Exceptions
    • Events
    • Verifications
    • Base class
    • Mock customization
    • Implicit mocks
    • Mock repository
    • Custom matchers
    • Multiple interfaces
    • Protected members
    • Generic methods
    • Delegates
  • AutoFixture
    • Quick glance at AutoFixture
    • Fixture
    • Create and Build
    • Type customization
    • Data annotations
    • Default configurations
    • Building custom types
    • Relays
    • Tricks
    • Idioms
    • Integration with NUnit
    • Integration with Moq
    • Combining AutoFixture with NUnit and Moq
    • Extending AutoFixture
  • Advanced topics
    • Testing HttpClient
Powered by GitBook
On this page
  • Reacting to method calls
  • Reacting to function calls
  • Reacting to asynchronous methods
  • Raising events manually
  1. Moq

Events

PreviousExceptionsNextVerifications

Last updated 4 years ago

Once a much more prominent feature of the .NET languages, events are not so commonly used anymore. Despite the fall of grace, many libraries, legacy and not, still use this feature.

Moq has some support for events, especially when following , like using event arguments inheriting from the EventArgs class. Whilst there is some support for so-called custom events, they will not be part of this guide. Please refer to the section related to events for this scenario.

The snippets of this section are based on the following interface

public class MessageEventArgs : EventArgs
{
    public string Message { get; set; }
}

public interface IService 
{
    event EventHandler<MessageEventArgs> Sent;

    event EventHandler<MessageEventArgs> Received;

    Task SendAsync(string message);

    void Send(string message);

    string Receive();

    Task<string> ReceiveAsync();
}

Reacting to method calls

One of the most common scenarios is raising an event upon the invocation of a configured method. This can be done by using the Raises construct.

var mock = new Mock<IService>();
mock.Setup(p => p.Send(It.IsAny<string>()))
    .Raises(e => e.Sent += null, (string msg) => new MessageEventArgs { Message = msg });

Usually, developers would use the Raises construct when the component under test relies on the method being invoked upon a method call. To test the setup to be correct, we can operate on the service as if we were the component under test. We can do this by using the Object property of the mock.

var service = mock.Object;

We then attach an event handler to the event exposed by the interface

service.Sent += (object sender, MessageEventArgs args) => TestContext.Progress.Writeline(args.Message);

Finally, we invoke the Send method by passing any string.

service.Send("Hello World");

If the setup is correct, we should see the "Hello world" string in the output stream.

Reacting to function calls

Like void methods, i.e. methods without return type, Moq can configure functions to raise an event when they are invoked.

The only difference is the requirement for configuring what the method will return before configuring the event Raise.

mock.Setup(p => p.Receive())
    .Returns("Hello")
    .Raises(e => e.Received += null, (string msg) => new MessageEventArgs { Message = msg });

Reacting to asynchronous methods

In the case we're dealing with asynchronous methods, few adjustments to the snippet above are required.

The rationale behind the adjustments is that asynchronous methods are normal methods returning a Task. Moq's strong type system does not make a strong distinction between asynchronous methods and normal methods with a return type.

mock.Setup(p => p.SendAsync(It.IsAny<string>()))
    .Returns(Task.CompletedTask)
    .Raises(e => e.Sent += null, (string message) => new MessageEventArgs { Message = message });

mock.Setup(p => p.ReceiveAsync())
    .ReturnsAsync("Hello")
    .Raises(e => e.Received += null, (string msg) => new MessageEventArgs { Message = msg });

Raising events manually

Another use case Moq is able to fulfill is the ability to manually raise events. The scenario is the one where the system under test is accepting a service that expose an event, subscribes to this event and reacts when it is raised.

mock.Raise(p => p.Sent += null, new MessageEventArgs { Message = "Hello world" });

This capability is normally used in the Act part of a properly written unit test.

established patterns
Moq Quick Start