LightMock

LightMock is a simple mocking library that can be used on platforms that does not allow dynamic code generation.

Installing

PM> Install-Package LightMock

This adds a reference to the LightMock in the target project.

The LightMock library is a a portable class library that makes it possible to use this across all platforms including iOS and Android.

Creating a mock object

Even though the mock objects are created manually, they can be reused in many scenarios.

As an an example we will use this simple interface.

public interface IFoo
{
    void Execute(string value);
    string Execute();        
}

The mock object implementing this interface looks like this

public class FooMock : IFoo
{
    private readonly IInvocationContext<IFoo> context;

    public FooMock(IInvocationContext<IFoo> context)
    {
        this.context = context;
    }

    public void Execute(string value)
    {
        context.Invoke(f => f.Execute(value));
    }

    public string Execute()
    {
        return context.Invoke(f => f.Execute());
    }        
}

Note: Only mocked methods needs to be implemented. Other methods that does not get invoked during testing can just throw a NotImplementedException.

Assertions

The Assert method is used to verify that the given method has been executed the expected number of times using the expected arguments.

//Arrange
var mockContext = new MockContext<IFoo>();
var fooMock = new FooMock(mockContext);

//Act
fooMock.Execute("SomeValue");

//Assert
mockContext.Assert(f => f.Execute("SomeValue"));

Note: Not specifying the expected number of invocations, means at least once.

If we don't care about the actual argument value, we can use a special class called The.

var mockContext = new MockContext<IFoo>();
var fooMock = new FooMock(mockContext);

fooMock.Execute("SomeValue");

mockContext.Assert(f => f.Execute(The<string>.IsAnyValue), Invoked.Once);

We call also use this class to perform custom verification.

var mockContext = new MockContext<IFoo>();
var fooMock = new FooMock(mockContext);

fooMock.Execute("SomeValue");

mockContext.Assert(f => f.Execute(The<string>.Is(s => s.StartsWith("Some"))), Invoked.Once);

Arrangements

We can use arrangements to add behavior to the mock object.

For instance we can set up the mock object to return a value.

var mockContext = new MockContext<IFoo>();
var fooMock = new FooMock(mockContext);
mockContext.Arrange(f => f.Execute()).Returns("SomeValue");

var result = fooMock.Execute();

Assert.AreEqual("SomeValue", result);

Throw an exception

var mockContext = new MockContext<IFoo>();
var fooMock = new FooMock(mockContext);
mockContext.Arrange(f => f.Execute("SomeValue")).Throws<InvalidOperationException>();
fooMock.Execute("SomeValue");

Throw an exception using a exception factory.

var mockContext = new MockContext<IFoo>();
var fooMock = new FooMock(mockContext);
mockContext.Arrange(f => f.Execute("SomeValue")).Throws(() => new InvalidOperationException());
fooMock.Execute("SomeValue");

Execute a callback

var mockContext = new MockContext<IFoo>();
var fooMock = new FooMock(mockContext);
string callBackResult = null;
mockContext.Arrange(f => f.Execute(The<string>.IsAnyValue))
    .Callback<string>(s => callBackResult = s);

fooMock.Execute("SomeValue");

Assert.AreEqual("SomeValue", callBackResult);