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+

Moq Partial Mocks

Moq is commonly used to create mock objects based upon interfaces. However, it can also be used to mock classes. This includes the possibility of creating partial mocks, where some members are intercepted with expectations whilst others run as normal.

Mocking Classes

When you are developing software using the SOLID principles you will often find that you are using dependency injection to provide an object with its dependencies. Usually the type declared for a dependency will be an interface, allowing you to provide objects of any class that implements the interface. During unit testing, you may inject a mock object based upon the interface, created using Moq. You can then take advantage of the Moq framework to isolate the class under test.

Moq, like other mocking frameworks, permits you to base your mock objects on classes as well as interfaces. Those classes can be abstract or concrete. You can then add expectations to the methods and properties of the class and use the mock object in much the same manner as one based upon an interface. The only limitation is that the members for which you wish to add expectations must be overridable; they must either be abstract or virtual and the class being mocked must not be sealed.

To demonstrate, let's create some classes to mock. Below you can see three classes. The Lander class is a base class for a device that can land on other planets and move around taking photographs and collecting samples. It has a single property, MotorStatus, that reports the status of the motor. In a real solution this would return a value determined by testing the motor. In the sample class it always returns, "OK".

The MarsLander class is a subclass of Lander. It adds two further properties. One describes the current charge status of the battery and the other is a flag indicating whether the lander's forward route is blocked. The final class, MarsLanderMonitor, is used to determine whether a Mars lander is able to move. It does this by checking the properties of a MarsLander object supplied via constructor injection. The lander may move if the battery charge is over 10%, the path is not blocked and the motor status is OK.

public class Lander
{
    public virtual string MotorStatus
    {
        get
        {
            // Code that checks the status of the lander's motor
            return "OK";
        }
    }
}


public class MarsLander : Lander
{
    public virtual int BatteryChargePercentage { get; set; }
    public virtual bool PathBlocked { get; set; }
}


public class MarsLanderMonitor
{
    MarsLander _lander;

    public MarsLanderMonitor(MarsLander lander)
    {
        _lander = lander;
    }

    public bool LanderCanMove()
    {
        return _lander.BatteryChargePercentage > 10 & !_lander.PathBlocked
            & _lander.MotorStatus == "OK";
    }
}

Let's now create a unit test. The test below creates a mocked MarsLander object using the same syntax that you would use for an interface. Three expectations set up the three key properties in a configuration that means the Mars lander can move. Next, a MarsLanderMonitor is instantiated, injecting the mocked MarsLander object. Finally, the assertion tests that the monitor class correctly indicates that the lander may move.

[TestFixture]
public class LanderMovementTests
{
    [Test]
    public void LanderCanMoveIfBatteryChargedMotorOKAndPathNotBlocked()
    {
        Mock<MarsLander> mockMarsLander = new Mock<MarsLander>();
        mockMarsLander.Setup(m => m.BatteryChargePercentage).Returns(25);
        mockMarsLander.Setup(m => m.PathBlocked).Returns(false);
        mockMarsLander.Setup(m => m.MotorStatus).Returns("OK");

        MarsLanderMonitor monitor = new MarsLanderMonitor(mockMarsLander.Object);

        Assert.IsTrue(monitor.LanderCanMove());
    }
}

Partial Mocks

A partial mock is a mock object based upon a class where one or more members have expectations and some members retain the original functionality of the class. When you mock a class using Moq, any members that do not have expectations use the behaviour from the underlying type.

To demonstrate, we will first modify the MarsLander class. We will add a new method that uses the same logic as the MarsLanderMonitor to determine whether the lander can move:

public class MarsLander : Lander
{
    public virtual int BatteryChargePercentage { get; set; }
    public virtual bool PathBlocked { get; set; }

    public bool CanMoveForward()
    {
        return BatteryChargePercentage > 10 & !PathBlocked & MotorStatus == "OK";
    }
}

We can now modify the MarsLanderMonitor class to use the CanMoveForward method of the injected MarsLander to determine if it can move:

public class MarsLanderMonitor
{
    MarsLander _lander;

    public MarsLanderMonitor(MarsLander lander)
    {
        _lander = lander;
    }

    public bool LanderCanMove()
    {
        return _lander.CanMoveForward();
    }
}

If you re-run the existing test you should still see a positive result. Again, the three key properties are intercepted by the mock object's expectations. The CanMoveForward method has no expectation so the standard functionality is used to determine the result, based upon the property values set in the expectations.

9 February 2012