BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Testing
.NET 3.5+

Mocking Multiple Interfaces with Moq

Injected dependencies often implement more than one interface. These may be used by the class receiving the injected object. When testing classes with such dependencies, it can be useful to create mock objects that implement multiple interfaces.

Interface Segregation Principle

When you develop in line with the SOLID principles, you try to adhere to a set of guidelines. One of these is the Interface Segregation Principle (ISP). The ISP states that classes should not be forced to depend upon interfaces that they don't use. When this principle is followed, you'll often create classes that implement multiple, small interfaces, rather than a single larger one.

Even when not using the SOLID principles you may create classes that implement several interfaces, perhaps in order to support polymorphism, or to allow interaction with standard .NET functionality. For example, you may create your own collection, which could implement IEnumerable<T>, or a class that uses unmanaged resources, in which case you would implement IDisposable.

If a type that implements multiple interfaces is used as a dependency of another class, you might need to mock it, using a framework such as Moq, in order to perform automated unit testing. It is common to create mocks for objects that implement a single interface. Moq also allows you to create mocks that implement two or more.

To demonstrate, we need some example code for which we can create tests. The following sample class is rather contrived but is suitable for our purposes. It includes a method that reads data from a string sequence and returns an array from its contents. For sequences that implement IDisposable, the source is disposed after it is read. For non-disposable sequences, the Dispose method is not called. We need to test both of these possible paths through the code.

public class StringSequenceReader
{
    IEnumerable<string> _source;

    public StringSequenceReader(IEnumerable<string> source)
    {
        _source = source;
    }

    public string[] ReadAll()
    {
        string[] results = _source.ToArray();

        IDisposable disposable = _source as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }

        return results;
    }
}

Testing the Sample Class

The first of the two tests is the simple one. For a sequence that does not implement IDisposable, we need to test that the correct array is generated by the ReadAll method. The test is shown below:

[TestFixture]
public class StringSequenceReaderTests
{
    [Test]
    public void NonDisposableSequencesCanBeRead()
    {
        var _mockStringSequence = new Mock<IEnumerable<string>>();
        _mockStringSequence.Setup(m => m.GetEnumerator())
            .Returns(new string[] { "A", "B", "C" }.Select(s => s).GetEnumerator());

        var reader = new StringSequenceReader(_mockStringSequence.Object);

        CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, reader.ReadAll());
    }
}

In the test we start by creating a mock object based upon IEnumerable<string>. We then set an expectation that makes our mock sequence return three strings. The expectation is set by intercepting calls to the GetEnumerator method and returning an enumerator containing fixed test data. Finally, the method under test is called and the assertion guarantees that the correct results are returned.

Mocking Multiple Interfaces

For our second test we want to ensure that calling the ReadAll method with a sequence that implements IDisposable both reads the sequence and disposes it. This means that our mock object needs to implement both IEnumerable<string> and IDisposable.

Creating a mock object with multiple interfaces is easy with Moq. First, we create the mock object for a single interface in the usual manner. We can then use the mock's As method to add interfaces. "As" is a generic method with a type parameter that defines the interface that you wish to add. Calling the method adds the necessary implementation details for the interface to the mock object. The method returns the modified object, cast to a mock of the specified type. Both the original reference and new reference can be used for setting and verifying expectations.

In the second test, we first create a mock for the IEnumerable<string> interface. The IDisposable interface is added with the As method, to create a second reference, cast as Mock<IDisposable>. The expectation that specifies the data that the mock object should return is set against the Mock<IEnumerable<string>> variable.

To perform the test, we call the ReadAll method and check the resultant array is correct. Finally, we verify that the Dispose method was called, using the Verify method of the Mock<IDisposable> variable.

[Test]
public void DisposableSequencesAreDisposedAfterReading()
{
    var _mockStringSequence = new Mock<IEnumerable<string>>();
    var _mockDisposable = _mockStringSequence.As<IDisposable>();
    _mockStringSequence.Setup(m => m.GetEnumerator())
        .Returns(new string[] { "A", "B", "C" }.Select(s => s).GetEnumerator());

    var reader = new StringSequenceReader(_mockStringSequence.Object);

    CollectionAssert.AreEqual(new string[] { "A", "B", "C" }, reader.ReadAll());
    _mockDisposable.Verify(m => m.Dispose());
}
11 October 2012