Mocklis documentation

_images/mocklis.png

Mocklis is a source code generator for .net (currently C#) which creates test doubles from interfaces, along with an api for providing these test doubles with behaviour.

Introduction

Mocklis is a mocking library for .net (currently C#) that

  • creates fake implementations of interfaces
  • that can be given specific behaviour
  • in an intellisense-friendly way
  • to be used as dependencies in components we want to test
  • letting us verify that they are correctly interacted with
  • without any use of reflection.

Let’s go over these points one by one.

Fake implementations of interfaces

With Mocklis you take an interface that defines a dependency for a component we wish to test, for instance this IConnection interface (with some details such as Message and MessageEventArgs removed for brevity):

public interface IConnection
{
    string ConnectionId { get; }
    event EventHandler<MessageEventArgs> Receive;
    Task Send(Message message);
}

Then you create an empty class implementing this interface, and decorate it with the MocklisClass attribute.

[MocklisClass]
public class MockConnection : IConnection
{
}

This will of course not compile in its current form. However, the presence of the MocklisClass attribute enables a code fix in Visual Studio.

_images/UpdateMocklisClass2.png

The code fix replaces the contents of the class as follows:

[MocklisClass]
public class MockConnection : IConnection
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    public MockConnection()
    {
        ConnectionId = new PropertyMock<string>(this, "MockConnection", "IConnection", "ConnectionId", "ConnectionId", Strictness.Lenient);
        Receive = new EventMock<EventHandler<MessageEventArgs>>(this, "MockConnection", "IConnection", "Receive", "Receive", Strictness.Lenient);
        Send = new FuncMethodMock<Message, Task>(this, "MockConnection", "IConnection", "Send", "Send", Strictness.Lenient);
    }

    public PropertyMock<string> ConnectionId { get; }

    string IConnection.ConnectionId => ConnectionId.Value;

    public EventMock<EventHandler<MessageEventArgs>> Receive { get; }

    event EventHandler<MessageEventArgs> IConnection.Receive {
        add => Receive.Add(value);
        remove => Receive.Remove(value);
    }

    public FuncMethodMock<Message, Task> Send { get; }

    Task IConnection.Send(Message message) => Send.Call(message);
}

You can see that the IConnection interface has been explicitly implemented, where the IConnection.ConnectionId property gets its value from a mock property with the same name. The IConnection.Receive event forwards adds and removes to another mock property, and the IConnection.Send method forwards calls to yet another mock property.

Note that the mock properties are generally properties even if the members they support aren’t: the IConnection.Send method is paired with a mock property of type FuncMethodMock, the IConnection.Receive event is paired with a mock property of type EventMock and so forth.

The practical upshot is that the IConnection interface is now implemented by the class, so that instances of the class can be used in places where the IConnection interface is expected.

Can be given specific behaviour

If we just use the class that was written for us in a real test it might not work as expected. The default behaviour for a newly constructed mock is to do as little as possible and return default values wherever asked, which is probably not what you wanted. The good news is that you can control this on a case by case basis using so-called steps.

[Fact]
public void ServiceCanCountMessages()
{
    // Arrange
    var mockConnection = new MockConnection();
    mockConnection.ConnectionId.Return("TestConnectionId");
    mockConnection.Receive.Stored(out var registeredEvents);

    var service = new Service(mockConnection);

    // Act
    registeredEvents.Raise(mockConnection, new MessageEventArgs(new Message("Test")));

    // Assert
    Assert.Equal("TestConnectionId", service.ConId);
    Assert.Equal(1, service.ReceiveMessageCount);
}

In this example, two steps were used. The Return step simply returns a value whenever the mock is used, and the Stored step tracks values written to the mock. In this case we also obtained a reference to the store, which tracked attached event handlers letting us raise an event on them for testing purposes. (Exercise for the reader: implement the Service class so that the test passes…)

This is of course just an introduction; see the Reference for a complete list of steps and other constructs used to control how Mocklis Classes work.

Intellisense friendly

Intellisense is a great feature of modern code editors, and Mocklis is written to make the most of it. Your Mocklis class exposes mock properties for members of implemented interfaces. These mock properties have extension methods for all of the different steps that they support, which allows Visual Studio will list the available steps through intellisense.

_images/Intellisense.png

Thanks to the extension method approach this list would also include any bespoke steps that have been added, whether defined in your own solution or in third party packages.

When mocking out method calls, all arguments are combined into a named value tuple (unless there’s exactly one in which case that one is used), which means that we get intellisense for using those parameters as well.

_images/intellisense2.png

Used as dependencies

Since Mocklis classes implement interfaces explicitly, we don’t risk a name clash with the mock properties (and indeed if possible, the mock properties will be given the same name as the interface member it’s paired with), and we can use the Mocklis class instance directly wherever the interface is expected.

Mocklis classes can also implement more than one interface in cases where the component it acts as a stand-in for would implement more than one interface. Common cases include where a class would implement a service interface and IDispose, or an interface with property accessors and INotifyPropertyChanged. If you need to mock out an enumerable, your Mocklis class can mock both IEnumerable<T> and IEnumerator<T> at the same time.

However, this also means that Mocklis classes can not create mocks for virtual members of an (abstract) base class, as these can not be explicitly implemented.

Verify interactions

There are a number of ways in which you can verify that the ‘component under test’ makes the right calls to your mocked dependency. There are a number of ways to do this using steps: simple cases:

  • If you have a method you don’t expect to be called, you can use a Throw step to throw an exception which will hopefully bubble up through your code and fail the test.
  • If you have a property, event or indexer you can use a Stored step and manually check that the right value was stored.
  • If you have a method then you can use a Func or Action step and let that set a flag which you can later manully assert.
  • You can use a Record step to record all interactions and check that the right interactions happened.

Mocklis also has a set of verification classes and interfaces that can be used to add checks to your mock properties and to verify the contents of Stored steps in a declarative way. You create a VerificationGroup, pass it to checks and verification steps, and assert everything in one go.

Take for instance this, somewhat contrived, test:

[Fact]
public void TestIndex()
{
    // Arrange
    var vg = new VerificationGroup("Checks for indexer");
    var mockIndex = new MockIndex();
    mockIndex.Item
        .ExpectedUsage(vg, null, 1, 3)
        .StoredAsDictionary()
        .CurrentValuesCheck(vg, null, new[]
        {
            new KeyValuePair<int, string>(1, "one"),
            new KeyValuePair<int, string>(2, "two"),
            new KeyValuePair<int, string>(3, "thre")
        });

    var index = (IIndex) mockIndex;

    // Act
    index[1] = "one";
    index[2] = "two";
    index[3] = "three";

    // Assert
    vg.Assert(includeSuccessfulVerifications: true);
}

This test will fail with the following output:

Mocklis.Verification.VerificationFailedException : Verification Failed.

FAILED: Verification Group 'Checks for indexer':
FAILED:   Usage Count: Expected 1 get(s); received 0 get(s).
Passed:   Usage Count: Expected 3 set(s); received 3 set(s).
FAILED:   Values check:
Passed:     Key '1'; Expected 'one'; Current Value is 'one'
Passed:     Key '2'; Expected 'two'; Current Value is 'two'
FAILED:     Key '3'; Expected 'thre'; Current Value is 'three'

Note that all verifications are checked - it will not stop at the first failure. By default the assertion will not show the Passed verifications (although the exception itself has a VerificationResult property, so you can always get to it). If you want to include all verifications in the exception message you need to pass true for the includeSuccessfulVerifications parameter, as was done in the sample above. Without it you would only see the lines that failed.

The null values in the example are placeholders for strings that would be added to the relevant lines in the result to help finding the culprit if the assertion failed.

Without reflection

Maybe this point should have gone in first. Mocklis does not use reflection to find out information about mocked interfaces, and it does not use emit or dynamic proxies to add implementations on the fly. Furthermore the mock instance and the object used to ‘program’ the mock are the same thing. There are pros and cons with this approach:

Pros

  • What you see is what you get. No code is hidden from view, and you can freely set break points and inspect variables as you’re debugging your tests.
  • You can easily extend Mocklis with your own steps, with whatever bespoke behaviour you might need.
  • Running your tests is significantly faster than it would have been with on-the-fly generated dynamic proxies.

Cons

  • Your project will include code for mocked interfaces, although that code can be reused by all tests using the interface.
  • The code in question has to be written, although the code generator bundled with Mocklis does this for you.
  • The design only really works for interfaces and not for mocking members of virtual base classes.

Installation

The quick version

Add the Mocklis nuget package to your test project.

This can be done with the NuGet browser in Visual Studio: Search for ‘Mocklis’ while on the Browse tab, and you should see the Mocklis packages and be able to add Mocklis to your project.

You’ll need to tick the checkbox that says ‘Include prerelease’ to see the Mocklis.Experimental package.

_images/nuget-new.png

The slighly longer version

There are two things that you’ll need to get hold of to run Mocklis.

Firstly there is a code generator that builds test double classes from interface definitions. The recommended way is to use a Roslyn Analyzer + Code Fix supplied in the form of the NuGet package Mocklis.MockGenerator. (If you’re building Mocklis from sources - kudos if you do - there is an embryo to a command-line version. This is just the absolute bare minimum needed to load a solution and update all MocklisClasses within.)

Then there is a library of pluggable ‘steps’ which provide bite-sized behaviours to the test doubles, along with some supporting code. This library is spread over a number of assemblies, most notably Mocklis.Core which contains the minimum amount of code required to build the test doubles, and Mocklis which you use in your tests to add behaviour. There’s also Mocklis.Experimental for steps whose design is still under development (read: steps that simply haven’t been axed yet…) and Mocklis.Serilog2 which contains a logging provider for Serilog 2.x.

Note that Mocklis.Experimental is going to stay a perpetual 0.x pre-release, so that it can have breaking changes without violating the semantic versioning rules.

Getting Started

A first mock

Mocking is the art of creating fake but controllable replacements for dependencies to code that we wish to test. However, for a simple walk-through of the functionality we’ll write a normal console application instead hoping that not too much is lost in the transition.

Let’s say we’re writing a component that reads numbers from standard input, sends them off to a web service for some calculation and writes the result to standard output.

The first step is to create two interfaces. One for interacting with the console, and one for the web service:

public interface IConsole
{
    string ReadLine();
    void WriteLine(string s);
}


public interface IService
{
    int Calculate(params int[] values);
}

And then we have our code that uses these two interfaces. Let’s add a constructor to our Program class, along with fields for the dependencies we’ll use.

public class Program
{
    public static void Main()
    {
    }

    private readonly IConsole _console;
    private readonly IService _service;

    public Program(IConsole console, IService service)
    {
        _console = console;
        _service = service;
    }
}

We will at some point write proper implementations of these interfaces, but for now we want to just mock them out.

Add two new classes, MockConsole and MockService. Let them implement their corresponding interface but otherwise remain empty. Reference the Mocklis NuGet package from your project and add the MocklisClass attribute to both classes.

For this walkthrough we need to add the ‘Strict’ parameter to the attributes - this is purely because we want to get exceptions for missing configurations to guide us to write more mocks. In your real life cases you may wish to have all mocks return default values instead of throwing exceptions in which case leave out the Strict parameter.

[MocklisClass(Strict = true)]
public class MockConsole : IConsole
{
}

[MocklisClass(Strict = true)]
public class MockService : IService
{
}

Now you can use the Update Mocklis Class code fix to create implementations for these interfaces. If you look at the MocklisClass attribute you’ll see that the first characters have an underline. This is Visual Studio hinting that there is a code fix available. Move your mouse over that area, and Visual Studio will provide you with a light-bulb. Click on the dropdown arrow and you’ll see a list of suggestions. Pick ‘Update Mocklis Class’ from the list, which will create an implementation of the class. Do this for both classes.

Instantiate these mocks in the static Main. Pass the instances to the constructor, create a non-static Run method and call it once the program instance has been created:

public static void Main()
{
    var mockConsole = new MockConsole();
    var mockService = new MockService();

    var program = new Program(mockConsole, mockService);
    program.Run();
}

public void Run()
{
}

Note that you didn’t have to cast mockConsole to IConsole, or mockService to IService. As long as the parameters accepting the mocked instances are of an implemented interface type, C# will perform an implicit cast.

Now we want to have a play with the interfaces. Let’s say we read numbers off standard input until we get an empty string, pass them all to the service, and then write the return value back to the console.

public void Run()
{
    var values = new List<int>();
    for (;;)
    {
        string s = _console.ReadLine();
        if (string.IsNullOrEmpty(s))
        {
            break;
        }
        values.Add(int.Parse(s));
    }

    var result = _service.Calculate(values.ToArray());
    _console.WriteLine(result.ToString());
}

If we try to run this we’ll fall over with a MockMissingException:

Mocklis.Core.MockMissingException: No mock implementation found for Method 'IConsole.ReadLine'. Add one using 'ReadLine' on your 'MockConsole' instance.

Let’s fix this with some mocking. First we want to return some strings from the mocked console. Let’s say the strings “8”, “13”, “21”, and an empty string. We should also add logging so we can follow what’s going on. Update Main as follows:

public static void Main()
{
    var mockConsole = new MockConsole();
    var mockService = new MockService();

    mockConsole.ReadLine.Log().ReturnEach("8", "13", "21", string.Empty);

    var program = new Program(mockConsole, mockService);
    program.Run();
}

Running the program now should give us the following output, most of it coming from the Log step.

Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '8'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '13'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '21'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: ''
Mocklis.Core.MockMissingException: No mock implementation found for Method 'IService.Calculate'. Add one using 'Calculate' on your 'MockService' instance.

Apparently we’re missing a mock for the IService.Calculate interface member. Let’s add that. In fact, let’s just pretend that the service adds up anything that is sent to it.

public static void Main()
{
    var mockConsole = new MockConsole();
    var mockService = new MockService();

    mockConsole.ReadLine.Log().ReturnEach("8", "13", "21", string.Empty);
    mockService.Calculate.Log().Func(m => m.Sum());

    var program = new Program(mockConsole, mockService);
    program.Run();
}

Which should now give us the following when we run the program:

Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '8'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '13'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '21'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: ''
Calling '[MockService] IService.Calculate' with parameter: 'System.Int32[]'
Returned from '[MockService] IService.Calculate' with result: '42'
Mocklis.Core.MockMissingException: No mock implementation found for Method 'IConsole.WriteLine'. Add one using 'WriteLine' on your 'MockConsole' instance.

Ok - so we’re still missing mocking out the WriteLine method. Let’s do so, add logging (as for the other ones) and also recording. A Record step will remember everything that was passed through it, and make it available using its out parameter as an IReadOnlyList.

Record steps, like Log steps, kind of expect you to chain further steps. They don’t make any decisions on their own. In this case we didn’t provide a further step so a default behaviour kicks in which is to accept any input and provide default values for any output required. This is normally the default behaviour as well for mocks that don’t have any steps defined at all, but we overrode that behaviour with the Strict = true switch in the MocklisClass attribute. If we want to throw for an incomplete mock as well (such as only providing a Log or Record without a subsequent step) you can set the VeryStrict = true attribute switch. If you’d done so, you would have needed to add a Dummy step after the RecordBeforeCall step.

Let’s also write out the first recorded value (in fact the only recorded value) to the real console so we can see the full thing end-to-end.

public static void Main()
{
    var mockConsole = new MockConsole();
    var mockService = new MockService();

    mockConsole.ReadLine.Log().ReturnEach("8", "13", "21", string.Empty);
    mockConsole.WriteLine.Log().RecordBeforeCall(out var consoleOut);
    mockService.Calculate.Log().Func(m => m.Sum());

    var program = new Program(mockConsole, mockService);
    program.Run();

    Console.WriteLine("The value 'written' to console was " + consoleOut[0]);
}

The parameter to RecordBeforeCall returns a list with the recorded values, which by default is just a list of the values passed to the method. You may want to store a subset of these or do some calculation on some values (or if they are mutable, get the current values before they’re changed) in which case you can add a selector func as a second parameter.

The program now completes without any exceptions, with the following output:

Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '8'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '13'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: '21'
Calling '[MockConsole] IConsole.ReadLine'
Returned from '[MockConsole] IConsole.ReadLine' with result: ''
Calling '[MockService] IService.Calculate' with parameter: 'System.Int32[]'
Returned from '[MockService] IService.Calculate' with result: '42'
Calling '[MockConsole] IConsole.WriteLine' with parameter: '42'
Returned from '[MockConsole] IConsole.WriteLine'
The value 'written' to console was 42

And with that we have written our first program with mocked interfaces using Mocklis. Of course normally we don’t work with mocking outside of unit tests, so this was for illustration only. But it should have given you some idea of what you can use Mocklis for.

Using Mocklis

Generating Mocklis classes

The Mocklis code generator takes a class which implements one or more interfaces and replaces the contents of that class with valid implementations of the interface memebers along with hooks through which you can control the behaviour of those members on a case by case basis. It does this by means of an analyzer/code-fix pair. Any class that is decorated with the MocklisClass attribute will make the code-fix available.

The code fix appears in Visual Studio as an underline of the first couple of characters in the attribute. Hover over these with the mouse, click on the arrow next to the light-bulb that appears and select ‘Update Mocklis Class’.

_images/generate.png

If you find it a bit tricky to find the right spot to hover over, you can change the ‘Serevity’ of the rule in your project as follows: In the solution explorer, expand References, Analyzers and Mocklis.MockGenerator. Right-click on the MocklisAnalyzer, and choose `Set Rule Severity`. Choose `Warning` and your entire MocklisClass will be underlined with a green squiggly line and you can update the class from anywhere.

The code generator will make use of any using statements it can find to storten names of types. It will not add any of its own, so if you generate a class and find that you end up with a lot of fully qualified types you can just add the relevant using statements, and then re-generate the class.

The details of the code generation can be found in the Reference section.

Attribute parameters

The generated code can be customised to a degree using properties on the MocklisClass attribute. The first two we’ll look at deal with how a mock should act when it’s got an incomplete or missing configuration, and the other two deal with generating code for methods returning values by reference.

One caveat: you can only set these properties to true or false. Anything else, like expressions, references to constants etc. will be interpreted as the default value for the parameter. Mocklis reads the parameters from code that has been parsed and analyzed, but it’s not running code. While it may be theoretically possible to do the required evaluations from the semantic model this has not been attempted.

Strictness parameters

Normally when you call a member on a mock that doesn’t have any steps assigned to it, it will do the least amount of work possible and return the least it can to the caller. In other words do nothing and return default where needed.

This may or may not be what you want. Another approach is that you should assign steps for all members that you expect to be used; if any of your uncofigured members are being called that’s a sign that your code is behaving in ways that you didn’t expect. To get mocks that throw an exception whenever this happens you add a Strict=true parameter to the MocklisClass attribute.

However we can be more draconian than that. Some steps will forward to further steps. If you want to throw not only on a completely unconfigured step, but also when a step is missing a step to forward to, you can add the VeryStrict=true parameter to the MocklisClass attribute.

The exception thrown is a MockMissingException, and you can ask to have it thrown regardless of strictness level by adding a Missing step. Likewise if you want to mimic the lenient behaviour, you can add a Dummy step.

For an example where the Strict=true parameter is used, see the Getting Started section.

Return by reference

C# 7 supports returning values by reference. However the ref keyword is not part of the returned type, and we cannot therefore just introduce a Mocklis mock where the return type is ref int rather than int. So we can cheat by pretending that the call is not by reference, and then we wrap it in an object at the last minute to fulfil the contract specified with the ref keyword in the interface.

Now, there are (at leaste) two reasons for returning values by reference. One is that we wish to modify the original value through the reference, the other is to improve performance where the returned type is larger than the size of a pointer. In the latter case we normally mark them as ref readonly to signal that you cannot make modifications through the reference. At least since C# 7.2 when this feature was introduced.

In the former case we usually need the reference to point to something known - so that the update has an effect that is visible to other code. In the second it doesn’t matter if the reference is to a newly created wrapper object that’s only there to fulfil a contract. Therefore Mocklis’ default behaviour differs between ref and ref readonly; for ref readonly we cheerfully wrap and for ref we use a virtual method fallback: Instead of normal mocks, we define virtual methods for all accessors of the mocked member and instead of adding steps you need to subclass the MocklisClass class and add bespoke implementations there. The base implementation for these methods is to always throw a MockMissingException regardless of strictness level. This is for technical reasons, the fallback is used in other cases where it turns out to be remarkably tricky to produce code that does nothing, returns default values and at the same time compiles…

But anyway.

You may want to use the fallback for ref readonly returns, and you might want to use the object wrapper solution for ref returns. The MockReturnsByRefReadonly parameter defaults to true (meaning to use mock properties and the wrapper solution), but you can set it to false if you like, which means to use virtual methods to control the behaviour of ref readonly returns. Likewise the MockReturnsByRef parameter defaults to false (meaning to use the fallback), but you can set it to true if you like, changing the code created to deal with ref returns to use mocks and the wrapper solution.

In the current version the parameters will affect all members in the class and there is no means by which we can chose what members to use what strategy for. There are no plans to change this but if you really need it please raise an issue on GitHub.

Adding steps

If you just need an object that implements an interface to pass to a constructor or method then you don’t need to add any steps at all - just an instance will do.

If the instance is used, but you don’t really care about what it does or returns you will get away with not doing any configuration, as long as you’ve created a lenient mocklis class, which is after all the default.

In other cases you’ll need to add configuration via steps. To add steps you can get a lot of help from the intellisense feature of your code editor. Given a variable that contains an instance of a Mocklis class, you can type that variable and a dot to get a list of mock properties to choose from. Select one, and type another dot and it will give you a list of all the valid steps you can add at this point.

Steps can be also chained together for more advanced cases. If a step can forward on call to other steps, type that dot directly after it (without ending the expression with a semi-colon) and intellisense will give you a list of valid steps to choose from.

Let’s say that you have mocked an int property, where the first time you call it expect the value 120, the second time you expect the value 210, and for any calls after that it should throw a FileNotFoundException. The following would do the trick:

var mock = new MockSample();
mock.TotalLinesOfCode
    .ReturnOnce(120)
    .ReturnOnce(210)
    .Throw(() => new FileNotFoundException());

The ReturnOnce steps can forward on calls, while the Throw step will always throw an exception and as such cannot chain in a further step. The extension methods used to add steps to mocks are written in such a way that you will get full intellisense and the ability to add steps to TotalLinesOfCode and ReturnOnce, but will not allow you to add anytihng to Throw (that is to say the Throw extension method returns void).

Since all steps are added through extension methods on the step type interface, any steps that you create yourself will automatically be available through intellisense.

More details can be found in the Reference section.

Work with type parameters

Roslyn, the code analysis and compilation framework that the Mocklis code generator uses, makes some things that look simple very difficult. Fine-tuning layout of code springs to mind. It also makes some things that seem insanely difficult almost trivial. Using type parameters is one such case.

There are two places where you can declare new type parameters, one is in the declaration of a class, struct or interface, and the other is when defining a method.

Type parameters on interfaces and classes

Mocklis can mock interfaces with type parameters, and indeed Mocklis classes can themselves be generic. You just need to make sure all types are closed when instantiating the class.

public interface IValueReader<out T>
{
    T Value { get; }
}

[MocklisClass]
public class MockValueReader<T> : IValueReader<T>
{
     // implementation removed for brevity
}

// usage:
var mock = new MockValueReader<string>();
mock.Value.Return("Hello world!");

Note that the steps remain strongly typed to the choice of type parameters; ‘mock.Value.Return(15)’ wouldn’t have compiled.

If a MocklisClass implements more than one interface, either directly or through other interfaces, each will be given its own implementation. A MocklisClass implementing IEnumerable<string>, which in turn extends IEnumerable, will have two different GetEnumerator methods; one from each interface, and they will need to be mocked out separately.

For a more extreme example run the code generator on the following class:

[MocklisClass]
public class MyDictionary<TKey> : IDictionary<TKey, string>
{
}

It will happily expand out all the interfaces necessary for the implementation (such as ICollection<KeyValuePair<TKey, string>>, and leave you with a Mocklis class you can instantiate with any key type you wish in your tests.

A corner case to be aware of is that you cannot implement interfaces that could unify for some combinations of actual types but not others. The following is an invalid declaration, but not because IEnumerable is declaced twice That is perfectly ok. The issue is that if T is substituted with ‘int’ then the interface declarations would unify, and otherwise they would remain separate. That is invalid.

public class Incompatible<T> : IEnumerable<T>, IEnumerable<int>
{
}

Type parameters on methods

For type parameters introduced on methods, Mocklis generates code with a slightly different syntax. Let’s say you have the following in your interface:

public interface ITypeParameters
{
    TOut Test<TIn, TOut>(TIn input) where TOut : struct;
}

Now Mocklis will generate a bit more code than normally:

[MocklisClass]
public class TypeParameters : ITypeParameters
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    private readonly TypedMockProvider _test = new TypedMockProvider();

    public FuncMethodMock<TIn, TOut> Test<TIn, TOut>() where TOut : struct
    {
        var key = new[] { typeof(TIn), typeof(TOut) };
        return (FuncMethodMock<TIn, TOut>)_test.GetOrAdd(key, keyString => new FuncMethodMock<TIn, TOut>(this, "TypeParameters", "ITypeParameters", "Test" + keyString, "Test" + keyString + "()", Strictness.Lenient));
    }

    TOut ITypeParameters.Test<TIn, TOut>(TIn input) => Test<TIn, TOut>().Call(input);
}

The difference is that the mock property has been replaced with a generic mock factory method, and this in turn requires a slightly different syntax when adding steps; where your ‘normal’ tests used to look like this:

var t = new TypeParameters;
t.Test.Return(15); // mock property

You’ll now write:

var t = new TypeParameters;
t.Test<string, int>().Func(int.Parse); // mock factory method
t.Test<int, int>().Func(a => a*2);     // mock factory method

Your mocks are made ‘per type combination’, and if you’re trying to use the mock with an un-mocked set of type parameters the result depends on the strictness level of your mock. There is no easy way to define a mock ‘for all possible combinations of types’, so Mocklis doesn’t support this. Note however that Mocklis passed on the type constraints to your factory method so you won’t be able to add steps to an invalid type combination.

Debugging tests

There are two approaches to debugging tests that have been taken into account for Mocklis. One is something akin to good old print-style debugging where a print statement would log any calls to a specific piece of code. Mocklis has a specific Log step that does roughly this.

Then, given that Mocklis generates source code you can easily set breakpoints as you would in any other code, step through code and watch variables as you normally do. The Mocklis libraries themselves are source linked debug builds, which means that you can get Visual Studio to let you step into the Mocklis source code and set breakpoints in the Mocklis sources almost as easily as you can do that in your own code.

To make this work you’ll need to switch off Just My Code and enable Source Links. Both from the OptionsDebugging section in Visual Studio. It’s also useful to clear Step over properties and operators.

_images/debugging-options.png

Now you can set breakpoints in your tests and use step into (F11) to drill into the Mocklis source code once you’re in debug mode. You can set breakpoints in any source file opened in this fashion. If you need to set a breakpoint in a file you don’t have opened but you know the name of the member, you can add this with the New dropdown in the Breakpoints window, or New Breakpoint from the Debug menu.

Refactoring tests

As the number of tests in your solution grows, it becomes increasingly important to make the test code itself streamlined and easy to work with. The classes you write with Mocklis are just normal code so most of the techniques you use for your normal development work equally well. In some cases you use patterns in your code base that would benefit from having steps tailored for them, we’ll go over how to do this in the section on Extending Mocklis. Find a few other techniques listed below.

Sharing setup logic

It’s a simple thing, but one that is easy to overlook. Since your Mocklis classes are just normal classes with source code you can write methods that operate on them. If you have a similar mock setup needed for a number of your tests, you can refactor that logic into a method of its own, or define extension methods on the Mocklis class.

Inheritance

The Mocklis code generator will not impose a base class for your Mocklis classes, nor will it prevent you from inheriting from them.

The only real restriction is that the Mocklis classes must not be partial (as that introduces a whole new level of corner case cacaphony), or static (as you cannot implement an interface ‘statically’ on a class).

But in short the class hierarchy is yours for making the most of; if you want to create a common ancestor for all your mocks you can certainly do so, and if you want to override a Mocklis class to centralise configuration or add new functionality just go ahead. Mocklis will create constructors as necessary, all of which will be protected if the Mocklis class is abstract and public otherwise.

You can also have Mocklis classes inherit from other Mocklis classes which lets you mock new interfaces for an existing Mocklis class. This could be useful if some of your tests require the mocked out dependency to also be disposable for instance… If you do use the MocklisClass attribute at more than one level of the class hierarchy you need to generate the code in the right order, from base class to derived class, otherwise you could get unresolved name clashes.

Invoking Mocks directly

Strictly speaking not something that helps you refactor tests, but still a technique that is useful to know when writing code that interacts with Mocklis classes: The mock properties that are added to your Mocklis classes will let you make the same calls to them as the explicitly implemented interface members would.

The different MethodMock classes (ActionMethodMock and FuncMethodMock) expose a Call method. The PropertyMock gives you access to a Value property, and the IndexerMock has an indexer defined so you can use it directly as an indexer.

It would be nice if the `EventMock` could have an event, but it seems it is not possible to declare an interface with a type from a type variable, regardless of whether it’s restricted to a `Delegate` type. However we have an `Add` and a `Remove` method that will let you do the same thing.

This can be particularly useful when unit testing steps themselves, but it can come in handy for writing normal tests as well.

[Fact]
public void SetThroughMock()
{
    var mock = new MockSample();
    var stored = mock.TotalLinesOfCode.Stored(0);

    // Write through the mock property
    mock.TotalLinesOfCode.Value = 99;

    // Assert through the stored step
    Assert.Equal(99, stored.Value);
}

What Mocklis can’t do

As with any framework, there have been trade-offs in the design.

Let’s start with the biggest one: Mocklis deals with interfaces only, the reason being that only interface members can be explicitly implemented. This makes things quite a bit easier for us - we don’t need to worry too much about naming clashes (that is to say the code generator does worry greatly about this, but the resulting code will be much less likely to have them). Then it may be that we want to use the same mocked class for more than one interface, and have the mock handle identical members on different interfaces in different ways.

So if you want to mock members of an abstract base class you can’t - unless you’re happy to manually write code to create mock properties and call them from your overridden memebers, and either do away with the ability to call ‘base’ or pass on the base call as another property as a lambda.

Then there are the so-called restricted types, comprised of a handful of core .net classes and ref structs. (The handful of classes are System.RuntimeArgumentHandle, System.ArgIterator, and System.TypedReference, and your ref structs are things like Span<T>.) These cannot be cast to object, and cannot be used as type parameters. As Mocklis uses type parameters to fit interface members into one of the four standard forms, these types can not be used by normal Mocklis mocks.

Mocklis will still implement these interface members explicitly, but instead of forwarding calls on to a mock property (or mock factory method) it will create virtual methods whose default implementation is to throw a MockMissingException. If you want to create bespoke behaviour you’ll have to subclass, and override. This is exactly the same trick as is used by default for some of the ref returns cases mentioned earlier.

Having said all of this, Mocklis should be able to provide something that compiles from any interface or (valid combination of) interfaces. In most cases this should should result in mock properties that you can use steps with. It should also avoid any name clashes, be it clashes with the name of the Mocklis class itself, any members defined in base classes, or clashes in type parameter names. If you do come up with a way of tripping up the code generator, please flag this on GitHub so it can be dealt with.

Reference

The reference section consists of four parts: standard steps, verifications, code generation and experimental stuff.

Standard Steps

Find below a discussion of all the steps in the standard Mocklis package that you can use. The list is, perhaps unfortunately, in alphabetic order. This means that some of the more common steps are listed towards the end, but it makes a little bit more sense as a reference section in this way.

Conditional steps

The conditional steps are steps that either branch out or cut short the invocation of a mocked member based on some condition.

The If steps branch to a different chain of steps if a given condition holds, with the option of joining the original remaining steps. In their basic form the decision is based on just information passed to the step, parameters to a method or key to an indexer. The InstanceIf step lets you make the decision based on the state of the whole mocked instance, and the IfAdd, IfRemove, IfGet and IfSet versions branch only for those actions of an event, property or indexer.

Here’s a mock setup for an indexer. Note the underlying name used for the indexer, which is used since it would not be well-formed C# to name a property this[]. The underlying name is usually Item - which is the reason why it’s not possible (unless the indexer name has been changed via the IndexerNameAttribute) to have a method named Item in a class with an indexer.

var mock = new MockSample();
mock.Item
    .If(g => g % 2 == 0, null, b => b.Return("Even"))
    .Return("Odd");

The null argument is for a parameter that decides when to use the if-branch when writing to the indexer.

If steps provide you with a joinpoint representing the non-if branch (called ‘ElseBranch’). In the following sample we have a property, where both the getter and setter are connected to the same Stored step. Only calls to the setter are logged to the console, however.

var mock = new MockSample();
mock.TotalLinesOfCode
    .IfSet(b => b.Log().Join(b.ElseBranch))
    .Stored(200);

The last sample for a conditional step uses the OnlySetIfChanged conditional which only exists for properties and indexers. When an attempt to ‘set’ a value is made, the step will first try to ‘get’ the value, check if it’s actually changed, and only ‘set’ the new value if it has.

var mock = new MockSampleWithNotifyPropertyChanged();
mock.PropertyChanged
    .Stored(out var pch);
mock.TotalLinesOfCode
    .OnlySetIfChanged()
    .RaisePropertyChangedEvent(pch)
    .Stored();

The combination of the OnlySetIfChanged, RaisePropertyChangedEvent and Stored steps is so common that there is a shorthand: StoredWithChangeNotification

var mock = new MockSampleWithNotifyPropertyChanged();
mock.PropertyChanged
    .Stored(out var pch);
mock.TotalLinesOfCode
    .StoredWithChangeNotification(pch);

Dummy steps

The Dummy steps will do as little as possible without throwing an exception. For a property or indexer, the step will do nothing for a setter, and return a default value for a getter. For an event, adding or removing an event handler do absolutely nothing, and for a method, it will not do anything with the parameters, and return default values for anything that needs returning, including out and ref parameters.

Note also that Dummy steps are final - you cannot add anything to follow them.

Join steps

We’ve already met the Join step in the sample code for If above, where it allows us to take any step (with the right form - that is member type and type parameters) and use as the next step. The missing piece is a method to designate a step as such a target, which is where the JoinPoint comes in.

Let’s say that we want to connect two properties to the same Stored step. The solution is to add a JoinPoint step just before the Stored step.

var mockDishes = new MockDishes();
mockDishes.Vichyssoise.JoinPoint(out var soup).Stored();
mockDishes.Revenge.Join(soup);

IDishes dishes = mockDishes;

dishes.Vichyssoise = "Best served cold";
Console.WriteLine(dishes.Revenge);

Note that any step would do for a Join, as long as we can get hold of it. The following would work equally well, taking the Stored step itself and using that as a join point:

var mockDishes = new MockDishes();
mockDishes.Vichyssoise.Stored(out var soup);
mockDishes.Revenge.Join(soup);

Lambda steps

These steps are constructed with either an Action or a Func, and when they are called the Action or Func will be run. In the case of Func the result of the call will be returned.

The names always contain the word Action or the word Func, but they are further qualified for non-method steps. Property and indexer steps are called GetFunc and SetAction while event steps are called AddAction and RemoveAction.

The lambda steps (and some of the other steps) have ‘instance’ versions where the current instance of the mock is passed as an additional parameter. This parameter is always untyped (well, passed as object), so you’ll need to cast it to one of the mocked interfaces (or the mocking class itself) for it to be of any use. These steps have the names of their non-instance counterparts prefixed with the word Instance (so that InstanceSetAction would exist as a property step to give an example).

Here’s an example where a Send method takes a message of some reference type and returns a Task:

var mockConnection = new MockConnection();
mockConnection.Send.Func(m => m == null
    ? Task.FromException(new ArgumentNullException())
    : Task.CompletedTask);

Log steps

Log steps are your quintessential debugging steps. They won’t do anything except write out anything that passes through them, by default to the console althought this can be tailored to your specific needs.

Therefore you can just add in a .Log() if you need to figure out what happens with a given mock. Note that they are best added early in a mock step chain if you want to get a faithful representation of what’s being called from the code you are testing, as steps can short-circuit calls or make calls of their own down the chain.

The Getting Started makes extensive use of Log steps.

If you’re working with Xunit as your test framework, you probably know that you cannot write to the Console and expect the strings written to be part of the test output, and that instead your test class accepts an ITestOutputHelper on the constructor. The recommended approach is to have your test class implement the ILogContextProvider interface.

public class Tests : ILogContextProvider
{
    public ILogContext LogContext { get; }

    protected Tests(ITestOutputHelper testOutputHelper)
    {
        LogContext = new WriteLineLogContext(testOutputHelper.WriteLine);
    }
}

Then you can replace all your calls to Log() with Log(this), and the lines will be written to the ITestOutputHelper.

There is also a specific LogContext for Serilog 2.x if you add the Mocklis.Serilog2 NuGet package. Create a SerilogContext with an ILogger that has a test-framework compatible sink, and set LogContext to that as in the example above.

Miscellaneous steps

Stuff that couldn’t really be placed in an existing category, and would have constituted a ‘one-step-only’ category if pushed…

Currently this (possibly expanding) category contains just the RaisePropertyChangedEvent step you saw in the last example of the Conditional steps category.

Missing steps

When one of these steps is invoked, it will throw a MockMissingException with information about the mock property itself.

The exception thrown could look something like this:

Mocklis.Core.MockMissingException: No mock implementation found for getting value of Property ‘ISample.TotalLinesOfCode’. Add one using ‘TotalLinesOfCode’ on your ‘MockSample’ instance.

Record steps

These steps will keep track of all the calls that have been made to them, so that you can assert in your tests that the right interactions have happened.

Each of the record steps will cater for one type of interaction only (method call, indexer get, indexer set, property get, property set, event add or event remove), and it will take a Func that transforms whatever is seen by the step to something that you want to store. They also provide the ‘ledger’ with recorded data as an out parameter.

There is currently no mechanism for letting record steps share these ‘ledgers’ with one another.

[Fact]
public void RecordAddedEventHandlers()
{
    // Arrange
    var mockSamples = new MockSampleWithNotifyPropertyChanged();
    mockSamples.PropertyChanged.RecordBeforeAdd(out var handlingTypes, h => h.Target?.GetType());

    // Act
    ((INotifyPropertyChanged)mockSamples).PropertyChanged += OnPropertyChanged;

    // Assert
    Assert.Equal(new[] { typeof(RecordSamples) }, handlingTypes);
}

Repetition steps

The Times steps look a little like conditional steps in that they add a separate step chain that can be taken. They differ from the if-step in that they cannot join back to the normal path, and that the separate path will only be used a given number of times.

In the current version a get or a set both count as a usage from the same pool for property and indexer mocks, as do adds and removes for an event mock.

For a sample see the next section, return steps.

Return steps

Arguably the most important step of them all. The Return step, only useable in cases where some sort of return value is expected, will simply return a value.

There are three versions, one that just returns a given value once, and passes calls on to subsequent steps on later calls, one that returns items from a list one by one, and one that returns the same value over and over.

Here’s code that shows how to use these, and the repetition step:

var mock = new MockSample();
mock.GuessTheSequence
    .Times(2, m => m.Return(1))
    .ReturnOnce(int.MaxValue) // should really be infinity for this sequence
    .ReturnEach(5, 6)
    .Return(3);

var systemUnderTest = (ISample)mock;

Assert.Equal(1, systemUnderTest.GuessTheSequence);
Assert.Equal(1, systemUnderTest.GuessTheSequence);
Assert.Equal(int.MaxValue, systemUnderTest.GuessTheSequence);
Assert.Equal(5, systemUnderTest.GuessTheSequence);
Assert.Equal(6, systemUnderTest.GuessTheSequence);
Assert.Equal(3, systemUnderTest.GuessTheSequence);
Assert.Equal(3, systemUnderTest.GuessTheSequence);
Assert.Equal(3, systemUnderTest.GuessTheSequence);
Assert.Equal(3, systemUnderTest.GuessTheSequence);

Stored steps

If the Return steps are the most used steps, the Stored steps are definitely the first runners up. These steps are defined for properties, playing backing field to the mocked property. They are also defined for indexers, where the backing structure is a dictionary which has the default return value for all non-set keys.

When creating a Stored step for a property you can give it an initial value, and for both properties and indexers you can use verifications to check that the stored value has been set correctly by the components that are under test.

Stored steps are also used with events where the steps act as storage for added event handlers. If you have a reference to the Stored step you can raise events on these handlers, simply by calling Invoke on the stored value. Alternatively, if your handler type is a generic EventHandler<> or one of a handful of very common event handler types including PropertyChangedEventHandler and the basic EventHandler, the Mocklis library provides you with Raise extension methods. These can be found in the Mocklis.Verification namespace.

[Fact]
public void RaiseEvent()
{
    var mock = new MockSample();
    mock.MyEvent.Stored<EventArgs>(out var eventStep);
    bool hasBeenCalled = false;

    ISample sample = mock;
    sample.MyEvent += (s, e) => hasBeenCalled = true;

    eventStep.Raise(null, EventArgs.Empty);
    // equivalent: eventStep.EventHandler?.Invoke(null, EventArgs.Empty);
    Assert.True(hasBeenCalled);
}

For indexers the step is called StoredAsDictionary as it holds different values for different keys. It will return a default value rather than throw if an empty slot is read from.

Throw steps

Super easy - with these steps you provide a Func that creates an exception. When called, the step will call this Func and throw the exception it returns.

Verification steps

Verification steps are steps that track some condition that can be checked and asserted against.

ExpectedUsage steps take a verification group as a parameter, along with the number of time they expect the mocked member to be called (which are tracked individually for getters, setters, adds, removes and plain method calls).

To get access to all steps and checks (see next section) for verifications you need to have the namespace Mocklis.Verification in scope via a using statement at the top of your file.

Verifications

If steps provide a means of creating behaviour for the system under test, verifications provide a means of checking that those behaviours have been used in the right way by the system under test.

Verifications come in two flavours. As normal steps they check data as it passes through them:

var vg = new VerificationGroup();
var mock = new MockSample();
mock.DoStuff
    .ExpectedUsage(vg, "DoStuff",  1);

...

vg.Assert();

… and also as ‘checks’ that verify some condition of an existing step:

[Fact]
public void JustChecks()
{
    var vg = new VerificationGroup();
    var mock = new MockSample();
    mock.TotalLinesOfCode
        .Stored(50)
        .CurrentValueCheck(vg, "TLC", 60);

    ISample sample = mock;
    sample.TotalLinesOfCode = 60;

    vg.Assert();
}

These are the only verifications in the framework at the moment. The expected usage steps work for all different member types, and track the different access methods independently. The current value checks exist for properties and indexers only, where the latter takes a list of key-value pairs to check.

To check that verifications have been met, call Assert on the top-most verification group, as done in the last example.

Mocklis Code Generation

An interface in C# can contain four different types of members: events, methods, properties and indexers. However each of them is just syntactic suger over one or two method calls. In Mocklis we represent each with a generic interface that encapsulates these method calls.

public interface IEventStep<in THandler> where THandler : Delegate
{
    void Add(IMockInfo mockInfo, THandler value);
    void Remove(IMockInfo mockInfo, THandler value);
}

public interface IIndexerStep<in TKey, TValue>
{
    TValue Get(IMockInfo mockInfo, TKey key);
    void Set(IMockInfo mockInfo, TKey key, TValue value);
}

public interface IMethodStep<in TParam, out TResult>
{
    TResult Call(IMockInfo mockInfo, TParam param);
}

public interface IPropertyStep<TValue>
{
    TValue Get(IMockInfo mockInfo);
    void Set(IMockInfo mockInfo, TValue value);
}

Ignoring the IMockInfo parameter for the moment, these represent what the different member types do, except they are modelled as if indexers always have one key, methods always one parameter and one result. Thanks to the value tuple feature we can pretend that multiple values are one.

Now it’s just a question of transforming any interface member into one of these four standard forms, and this is done by the code generated my Mocklis.

In the next few sections we’ll go over the different things that Mocklis can generate for us. There are a number of corner cases in particular to do with naming, and we won’t go over all of them here. For a reasonably complete set of cases see the Mocklis.MockGenerator.Tests project in the Mocklis source code.

Event mocks

The simplest (as in has the fewest special cases) thing to implement is events. An event has to be of a delegate type and is always represented by an Add/Remove pair of methods, which is exactly what the IEventStep interface models.

Let’s say that we have an interface with an event.

public interface ITestClass
{
    event EventHandler MyEvent;
}

The generated code for such an interface consists of three parts. The explicitly implemented event itself just forwards adds and removes to an EventMock, which is itself creted in the constructor and exposed as a property.

[MocklisClass]
public class TestClass : ITestClass
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    public TestClass()
    {
        MyEvent = new EventMock<EventHandler>(this, "TestClass", "ITestClass", "MyEvent", "MyEvent", Strictness.Lenient);
    }

    public EventMock<EventHandler> MyEvent { get; }

    event EventHandler ITestClass.MyEvent { add => MyEvent.Add(value); remove => MyEvent.Remove(value); }
}

That’s really all there is to it. A common question is how to raise events. The fact that an event itself has little to do with raising events is a common C# ‘gotcha’. The event is only about combining event handlers through the add and remove accessors. To raise an event you need to call Invoke on the resulting combined handler. In Mocklis you need to add a Stored step to an event in order to correctly remember and combine handlers so you have something to raise the event on. Then you can use the handler exposed by the Stored step. See the documentation for a Stored step above for a complete example.

Events can be generic-ish. For some reason it’s not possible to have an event of type parameter type, even if that type parameter is contrained to delegate type. But you can have an event of a generic delegate type, such as EventHandler<T>.

Property mocks

Like an event, a property has two accessor methods. In this case one to get a value, and one to set a value. Unlike an event you do not need to use both of them, as a property can be readonly or writeonly. The generated mock property doesn’t make a distinction, and the generated code for an interface with three string propertis with different access looks like this:

[MocklisClass]
class TestClass : ITestClass
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    public TestClass()
    {
        ReadOnly = new PropertyMock<string>(this, "TestClass", "ITestClass", "ReadOnly", "ReadOnly", Strictness.Lenient);
        WriteOnly = new PropertyMock<string>(this, "TestClass", "ITestClass", "WriteOnly", "WriteOnly", Strictness.Lenient);
        ReadWrite = new PropertyMock<string>(this, "TestClass", "ITestClass", "ReadWrite", "ReadWrite", Strictness.Lenient);
    }

    public PropertyMock<string> ReadOnly { get; }

    string ITestClass.ReadOnly => ReadOnly.Value;

    public PropertyMock<string> WriteOnly { get; }

    string ITestClass.WriteOnly { set => WriteOnly.Value = value; }

    public PropertyMock<string> ReadWrite { get; }

    string ITestClass.ReadWrite { get => ReadWrite.Value; set => ReadWrite.Value = value; }
}

Properties can be generic. Properties can also be of restricted type, in which case the generated code will fall back to virtual methods and you’ll need to subclass and override to add behaviour rather than using steps.

public interface ITestClass
{
    Span<string> SpanProperty { get; set; }
}

[MocklisClass]
class TestClass : ITestClass
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    protected virtual Span<string> SpanProperty()
    {
        throw new MockMissingException(MockType.VirtualPropertyGet, "TestClass", "ITestClass", "SpanProperty", "SpanProperty");
    }

    protected virtual void SpanProperty(Span<string> value)
    {
        throw new MockMissingException(MockType.VirtualPropertySet, "TestClass", "ITestClass", "SpanProperty", "SpanProperty");
    }

    Span<string> ITestClass.SpanProperty { get => SpanProperty(); set => SpanProperty(value); }
}

Indexer mocks

Indexers are, loosely speaking, properties with a parameter list, so most of the discussion for properties goes for indexers as well. Even thought indexers are declared with the this keyword, they have an internal name (that can be changed with the IndexerName attribute), and the default name is Item.

In mocklis an indexer has a getter with one parameter type, and a return type, and a setter with one parameter type and a value type, but indexers can have more than one parameter. Here Mocklis uses ValueTypes to turn multiple types into one.

public interface ITestClass
{
    string this[int row, int col] { get; set; }
}

[MocklisClass]
class TestClass : ITestClass
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    public TestClass()
    {
        Item = new IndexerMock<(int row, int col), string>(this, "TestClass", "ITestClass", "this[]", "Item", Strictness.Lenient);
    }

    public IndexerMock<(int row, int col), string> Item { get; }

    string ITestClass.this[int row, int col] { get => Item[(row, col)]; set => Item[(row, col)] = value; }
}

Note that the mock property uses the internal name of the indexer, it’s not possible to expose a this[] property. Otherwise anything that goes for a property also goes for an indexer.

Method mocks

We’re discussing methods last because these have the largest number of different cases, even thought the IMethodStep interface only has one member. As for the indexer, condensing multiple parameters into one is done using ValueTuples. We cannot encode whether a parameter is in, out or ref in the value tuple, so instead an out parameter is added to the return type, and a ref parameter is added both as a normal parameter an as part of the return type. This means that we can have multiple return types, and again these are combined into a single ValueTuple.

The canonical example is the TryParse. Notice that the mock takes a string and returns a (bool, int) pair. By naming the individual types in the ValueTuple we get intellisense, and the name returnValue is given to the value returned from the mocked method.

public interface ITestClass
{
    bool TryParse(string text, out int result);
}

[MocklisClass]
class TestClass : ITestClass
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    public TestClass()
    {
        TryParse = new FuncMethodMock<string, (bool returnValue, int result)>(this, "TestClass", "ITestClass", "TryParse", "TryParse", Strictness.Lenient);
    }

    public FuncMethodMock<string, (bool returnValue, int result)> TryParse { get; }

    bool ITestClass.TryParse(string text, out int result)
    {
        var tmp = TryParse.Call(text);
        result = tmp.result;
        return tmp.returnValue;
    }
}

Method mocks can also return values by reference, and like out or ref parameters, the information that the value is to be returned by ref isn’t part of the return type and thus cannot be encoded in the type parameters of the mock itself. Mocklis can handle this by treating the mock as if it was a normal non-ref method, and then wrap the return value in an object so that we can return a reference at the last minute. Granted, this doesn’t provide the performance benefit that is sometimes looked for when using ref return values, but for tests this is usually good enough.

public interface ITestClass<in TKey, out TValue> where TValue : new()
{
    ref readonly int GetRef();
}

[MocklisClass]
class TestClass<T, U> : ITestClass<T, U> where U : new()
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    public TestClass()
    {
        GetRef = new FuncMethodMock<int>(this, "TestClass", "ITestClass", "GetRef", "GetRef", Strictness.Lenient);
    }

    public FuncMethodMock<int> GetRef { get; }

    ref readonly int ITestClass<T, U>.GetRef() => ref ByRef<int>.Wrap(GetRef.Call());
}

The default is to treat ref readonly returns in this manner, while using the virtual method fallback for ref returns. This can be controlled with attribute parameters as discussed in the Using Mocklis section.

Since method calls can have zero (or more) parameters and a void (or non-void) return type, we end up with four different types of methods: nothing->nothing, nothing->something, something->nothing and something->something. To keep the mock class a little more readable there are four different method mock types (in the example above FuncMethodMock was used) that all implement the ICanHaveNextMethodStep interface. There are also cases where the steps themselves come in different flavours depending on whether there are parameters and/or return types. The trick used by Mocklis is to represent a missing type with ValueTuple, but this also means that there might be more than one valid step to use.

As for properties and indexers, methods can use type parameters introduced by the interface they’re defined in. But methods can also introduce type parameters of their own. Since these type parameters won’t be closed we cannot create a mock property directly with them - we would need to have individual properties of all possible combinations of types. This is clearly impractical, so instead we create them as needed and store them in a dictionary keyed on the actual types used for each instance.

The generated code therefore contains a mock factory method instead of a mock property.

public interface ITestClass
{
    string Write<T>(T param);
}

[MocklisClass]
class TestClass : ITestClass
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    private readonly TypedMockProvider _write = new TypedMockProvider();

    public FuncMethodMock<T, string> Write<T>()
    {
        var key = new[] { typeof(T) };
        return (FuncMethodMock<T, string>)_write.GetOrAdd(key, keyString => new FuncMethodMock<T, string>(this, "TestClass", "ITestClass", "Write" + keyString, "Write" + keyString + "()", Strictness.Lenient));
    }

    string ITestClass.Write<T>(T param) => Write<T>().Call(param);
}

Constructors

The mocks are initialised in the constructor. For a MocklisClass that doesn’t derive from another class (that is to say that derives directly from object) a default constructor will be added if there are mocks to initialise. The constructors are protected if the MocklisClass is declared as abstract, and public otherwise.

If the MocklisClass does derive from another class, all public and protected constructors from that base class will be given a corresponding constructor in the MocklisClass, passing on parameters as necessary.

If you look at the constructors in the examples given, each of the mock properties take a couple of parameters, a reference to the mock instance itself, and a couple of strings with the name of the mock class, the names of the interface and member, and the name of the mock property (which often but not always is the same as the name of the member). It also takes the strictness used when creating the MocklisClass so that it can react correctly in the cases where the configuration is missing or incomplete. This is exactly what can be found in the IMockInfo interface that is on every call on every I-membertype-Step interface. Steps can take advantage of this information if they want to; indeed the Missing step picks up the information from this parameter to provide the best possible exception message for the user.

Name clashes

There are cases where the generated code for mocks would clash with either each other or with identifiers already declared in base classes. In these cases Mocklis will add a numerical suffix to the introduced identifier. To take a very simple example, IEnumerable<T> derives from IEnumerable, and both have a GetEnumerator method. The generatod code looks like the following, and unfortunately you have to know which method you want to add a step to and use the corresponding name.

[MocklisClass]
class TestClass : IEnumerable<int>
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    public TestClass()
    {
        GetEnumerator = new FuncMethodMock<IEnumerator<int>>(this, "TestClass", "IEnumerable", "GetEnumerator", "GetEnumerator", Strictness.Lenient);
        GetEnumerator0 = new FuncMethodMock<System.Collections.IEnumerator>(this, "TestClass", "IEnumerable", "GetEnumerator", "GetEnumerator0", Strictness.Lenient);
    }

    public FuncMethodMock<IEnumerator<int>> GetEnumerator { get; }

    IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator.Call();

    public FuncMethodMock<System.Collections.IEnumerator> GetEnumerator0 { get; }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator0.Call();
}

Name clashes can also appear in the type parameter names, and in the types used to create a ValueTuple. When creating a ValueTuple we could clash with the default names Item1, Item2 and so forth, so Mocklis will rename these as well when needed.

Type parameter substitutions

The type parameter names declared by an interface, and the type parameter names used when referencing that interface do not need to be the same. Mocklis does substitutions where necessary, and sorts out situations where there would be a name clash.

Here’s a simple example - the interface calls the key TKey, but the class uses T, therefore all instances of TKey in the interface have been replaced with T in the class, and the same goes for TValue and U.

public interface ITestClass<in TKey, out TValue>
{
    TValue GetValue(TKey key);
}

[MocklisClass]
class TestClass<T, U> : ITestClass<T, U>
{
    // The contents of this class were created by the Mocklis code-generator.
    // Any changes you make will be overwritten if the contents are re-generated.

    public TestClass()
    {
        GetValue = new FuncMethodMock<T, U>(this, "TestClass", "ITestClass", "GetValue", "GetValue", Strictness.Lenient);
    }

    public FuncMethodMock<T, U> GetValue { get; }

    U ITestClass<T, U>.GetValue(T key) => GetValue.Call(key);
}

Experimental Stuff

Mocklis has a project & associated NuGet package for experimental things: Mocklis.Experimental. It is meant for things that are in a bit of flux and may either graduate to the main Mocklis package, or be found wanting and deleted. Think of it as an incubation space for new functionality. It will not follow the versioning of the other Mocklis NuGet packages, but will stay perpetually pre-release.

At the moment it only contains the Gate step.

Gate steps

The idea behind the Gate step is that it will complete a Task (as in Task Parallel Library), when the step is called. The Task can then be used to drive other things happening in the step, effectively forcing a strict ordering of events in the face of many threads running.

The syntax is still very experimental - it currently only exists for ‘Method’ mocks, and might well be killed off altogether…

public async Task SuccessfulPing()
{
    // Arrange
    var mockConnection = new MockConnection();
    mockConnection.Send
        .Gate(out var sendGate)
        .Return(Task.CompletedTask);
    mockConnection.Receive
        .Stored<MessageEventArgs>(out var messageReceive);
    var pingService = new PingService(mockConnection);

    // Act
    var ping = pingService.Ping();
    await sendGate;
    messageReceive.Raise(mockConnection, new MessageEventArgs(new Message("PingResponse")));
    var pingResult = await ping;

    // Assert
    Assert.True(pingResult);
}

Extending Mocklis

Writing new steps

The best way to learn about writing steps is to look at the source code for existing steps. But in the interest of documentation, here’s a sample.

Disclaimer: This is a silly example. You would never write test code that depends on the time of day. It was chosen because you can be absolutely certain that this step won’t ever clash with anything in the Mocklis libraries themselves. (We sincerely hope…)

Phase 1: Write a step

If you are writing a ‘final’ step, implement the I-memberType-Step interface. You just need to implement this interface and you’re done.

If you are writing a non-final step, consider (as in: it is very strongly recommended) subclassing the memberType-StepWithNext class, and override the I-memberType-Step members as you see fit. Otherwise you need to implement strictness checks yourself, and the base class will give you overridable members to plug in your specific functionality where the base implementation will forward to a next step. Let’s say we’re writing a step to nudge our overworked developers to go home by starting to throw exceptions after 5 o’clock.

Let’s also say we’re writing this for a property. We’ll end up with something like this:

public class EndOfDayPropertyStep<TValue> : PropertyStepWithNext<TValue>
{
    private readonly int _cutOffHour;

    public EndOfDayPropertyStep(int cutOffHour)
    {
        _cutOffHour = cutOffHour;
    }

    private void ThrowIfLate()
    {
        if (DateTime.Now.Hour >= _cutOffHour)
        {
            throw new Exception("It's late - start considering calling it a day.");
        }
    }

    public override TValue Get(IMockInfo mockInfo)
    {
        ThrowIfLate();
        return base.Get(mockInfo);
    }

    public override void Set(IMockInfo mockInfo, TValue value)
    {
        ThrowIfLate();
        base.Set(mockInfo, value);
    }
}

Phase 2: Write an extension method

If you wanted to use the new step as is, you would have to create an instance of it and feed to the SetNextStep method of the previous step. To enable the fluent syntax you’ll need to add the step as an extension method on the IPropertyStepCaller interface.

public static class EndOfDayStepExtensions
{
    public static IPropertyStepCaller<TValue> EndOfDay<TValue>(
        this IPropertyStepCaller<TValue> caller,
        int? cutOffHour = null)
    {
        return caller.SetNextStep(new EndOfDayPropertyStep<TValue>(cutOffHour ?? 17));
    }
}

Notice the naming convention: The EndOfDayPropertyStep is added as an extension method named EndOfDay, taking an IPropertyStepCaller as its ‘this’ parameter. An EndOfDayMethodStep would be added as an extension method also named EndOfDay. There is no risk of a naming clash, as the parameter types will differ.

Now you can use your new step:

var mock = new MockSample();
mock.TotalLinesOfCode
    .EndOfDay()
    .Return(50);

With the obvious (well - depending on what time it is) result:

System.Exception: It's late - start considering calling it a day.

Phase 3: Generalise

The last phase is to look at your newly created step and consider whether it can be used in other situations. You should extend the step to the different member types if possible.

In some cases the way a step works could depend on the complete state of the mock instance. In these cases you should add new steps with the same name as your existing ones, but prefixed with ‘Instance’. For this version you pass on the IMockInfo.Instance to the construct you have that uses the instance. Look at the existing Lamdba steps for the quintessential implementation, however the Record and If steps also have instance versions.

If you work with steps for methods, you might need to consider having different versions depending on whether your methods take parameters or not, and whether they return things or not. For the lamdba steps there are two FuncMethodStep classes, and two ActionMethodStep classes.

public class FuncMethodStep<TParam, TResult> : IMethodStep<TParam, TResult>
{
}

public class FuncMethodStep<TResult> : IMethodStep<ValueTuple, TResult>
{
}

public class ActionMethodStep<TParam> : IMethodStep<TParam, ValueTuple>
{
}

public class ActionMethodStep : IMethodStep<ValueTuple, ValueTuple>
{
}

Note how the ones that don’t funnel data constrict either TParam and/or TResult to be of type ValueTuple (read: void or unit depending on how you were brought up). While more than one of these might be eligible for use in a given scenario, the design goal is that there should always be one that doesn’t require the user to pass manually created ValueTuple instances.

Writing new verifications

The idea behind Mocklis’ verifications is to create a tree of binary checks that can be verified in one go. When verified, a read-only data structure is created, that contains information about all the verifications and whether they were successful or not.

A verification implements the IVerifiable interface:

public interface IVerifiable
{
    IEnumerable<VerificationResult> Verify();
}

…where a truncated version of the VerificationResult struct is as follows:

public struct VerificationResult
{
    public string Description { get; }
    public IReadOnlyList<VerificationResult> SubResults { get; }
    public bool Success { get; }

    public VerificationResult(string description, bool success)
    {
        Description = description;
        SubResults = Array.Empty<VerificationResult>();
        Success = success;
    }

    public VerificationResult(string description, IEnumerable<VerificationResult> subResults)
    {
        Description = description;
        if (subResults is ReadOnlyCollection<VerificationResult> readOnlyCollection)
        {
            SubResults = readOnlyCollection;
        }
        else
        {
            SubResults =
                new ReadOnlyCollection<VerificationResult>(
                    subResults?.ToArray() ?? Array.Empty<VerificationResult>());
        }

        Success = SubResults.All(sr => sr.Success);
    }
}

The first constructor is for leaf nodes, and the second is for branch nodes. Note that if any leaf node fails, all branch nodes up to the root from that leaf node will have failed as well. Therefore if the root succeeds, we can be sure that all leaf nodes will have as well.

Verifications can either be written as steps. These steps implement the IVerifiable interface, and the extension method takes a VerficationGroup as a parameter and attach the created step to that group.

Let’s say we’re creating a Method step to check that the method has indeed been called. Subclass MethodStepWithNext, override Call to set a flag that it has been called, and implement IVerifiable to return a VerificationResult.

public override TResult Call(IMockInfo mockInfo, TParam param)
{
    _hasBeenCalled = true;
    return base.Call(mockInfo, param);
}

public IEnumerable<VerificationResult> Verify()
{
    var text = "Method should be called, " +
        (_hasBeenCalled ? "and it has." : "but it hasn't.");
    yield return new VerificationResult(text, _hasBeenCalled);
}

Then we add the step to the verification group in its extension method:

public static IMethodStepCaller<TParam, TResult> HasBeenCalled<TParam, TResult>(
        this IMethodStepCaller<TParam, TResult> caller,
        VerificationGroup collector)
    {
        var step = new HasBeenCalledMethodStep<TParam, TResult>();
        collector.Add(step);
        return caller.SetNextStep(step);
    }

But we may want to check some condition without it being a step in its own right. All the Stored steps (which would be property, indexer and event) implement an interface to directly access what is being stored. An implementation of IVerifiable that is not a step in its own right is called a ‘check’, and writing one is straightforward:

Create a class, have it implement IVerifiable. Let the constructor take as input anything it needs to verify that the condition for the verification has been met. In the case of the CurrentValuePropertyCheck that checks that a Stored property step has the right value this includes:

  • The IStoredProperty to check the value of.
  • A string that allows us to give the verification a name to identify it by. This is genarally a recommended thing to do.
  • The expected value.
  • An equality comparer to check that the value is right, where the default null will be replaced with EqualityComparer.Default.

Then the Verify method checks the condition and returns one or more verification results.

The extension method is slighly different from the one used for steps. For one thing there is no chaining going on through a SetNextStep method. Just use the interface exposed as a ‘this’ parameter, add a VerificationGroup, use the former to create the check instance and the latter to make the check available from the group. Then it can just return the access interface again if we want to attach more checks.

Something like this:

public static IStoredProperty<TValue> CurrentValueCheck<TValue>(
    this IStoredProperty<TValue> property,
    VerificationGroup collector,
    string name,
    TValue expectedValue,
    IEqualityComparer<TValue> comparer = null)
{
    collector.Add(new CurrentValuePropertyCheck<TValue>(property, name, expectedValue, comparer));
    return property;
}

Writing a new logging context

This has got to be a very rare occurrance. Given that the Log steps are mainly there to aid in debugging your mocks, the default behaviour to just write log statements to the console is normally good enough.

If you need to write them to somewhere else, such as to an xUnit ITestOutputHelper, you can pass an Action<string> to the WriteLineLogContext constructor and pass that to the Log steps.

However if you need to do more advanced stuff, such as logging mock interactions as structured data you can create a bespoke implementation of the ILogContext interface. This interface has individual methods for all different logging calls made by Mocklis. Implementing it should be a straightforward, if boring, exercise, and you can always look at the source code for the Mocklis.Serilog2 for an example of how it can be done.

Frequently Asked Questions

ValueTuple

When I’m creating mocks for methods I often come across mock steps that take ``ValueTuple`` as parameters, but I didn’t have anything like that in my original interfaces - what’s going on?

Mocklis strives to map members of interfaces into one of four formats (for events, indexers, methods and properties respectively). In the case of a method the format is simply an ability to call the method with one parameter and one return type. If you have many parameters, they will be grouped together as named members of a value tuple, and in the case where you don’t have any parameters or a void return type, the ‘empty’ ValueTuple will be used. It is essentially just a struct with no members, and is the closest thing to a void type that the .net framework contains.

For the lambda steps (Func and Action, and the instance versions thereof) there are overloads that require the parameters to be of type ValueTuple, and the action versions require the return type to be a ValueTuple as well. This is simply to provide a nicer and terser syntax, but there is no way to prevent intellisense to suggest the fuller version as well. To make it a little bit more concrete, consider the following interface:

public interface IMisc
{
    void SayHello();
    int ScaleByTheAnswer(int p);
}

[MocklisClass]
public class Misc : IMisc
{
   . . .
}

When we are creating a mock for the SayHello method, we have four different (but ultimately equivalent) ways to go about it:

var misc = new Misc();

misc.SayHello.Action(() =>
{
    Console.WriteLine("Hello");
});

misc.SayHello.Action<ValueTuple>(_ =>
{
    Console.WriteLine("Hello");
});

misc.SayHello.Func<ValueTuple>(() =>
{
    Console.WriteLine("Hello");
    return ValueTuple.Create();
});

misc.SayHello.Func<ValueTuple, ValueTuple>(_ =>
{
    Console.WriteLine("Hello");
    return ValueTuple.Create();
});

Of course the compiler infers the type parameters - they’re just there for clarity. On the other hand for the ScaleByTheAnswer method, we only have one overload that works, since this method both accepts and returns stuff.

var misc = new Misc();

misc.ScaleByTheAnswer.Func<int, int>(i =>
{
    return i * 42;
});

Again the compiler infers the type parameters, and you can of course shorten the lambda considerably. But in short: you may be presented with steps that use ValueTuple, in which case it generally pays to look for versions of those steps that don’t.

“Missing” mock

When my mock is called, it throws a ``MockMissingException``. But I’m absolutely certain that I did provide a mock implementation. What’s going on?

Update: This now only happens when the MocklisClass attribute was declared with a VeryStrict = true parameter. The new behaviour (since version 0.2.0-alpha) for both lenient and strict (as in not ‘very strict’) mocks is that all steps assume an implicit Dummy step for all further extension points. In ‘very strict’ mode there is an implicit Missing step instead and an exception will be thrown.

You can think of the ‘very strict’ mode as ‘treat warnings as errors’. It’s a bit of a pain but it can help find issues with your mocks.

The solution is to chain a next step that does what you want the mock to do, be it a Dummy step, a Return step or anything else.

With an interface borrowed from the previous faq entry, here is a case which would throw the exception when used:

var misc = new Misc();

misc.ScaleByTheAnswer.Log();

The Log step will log the call, and then forward to the ‘default’ next step which (perhaps surprisingly) throws. Provide a next step as follows and it doesn’t throw:

var misc = new Misc();

misc.ScaleByTheAnswer.Log().Dummy();

And of course it doesn’t have to be Dummy(); - looking at the name of the method an appropriate mock might be .Func(i => i * 42);

Indices and tables