BlackWaspTM
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());
    }
}
9 February 2012