Mocking is the art of creating specialised implementations ("Mocks") of a system's
dependencies.
These let us write unit tests to verify that the system 'does the right things' when interacted with in
different ways.
To streamline the creation of these Mocks we use a Mocking framework. These traditionally generate Mocks at run-time.
Mocklis is a little different. It generates source code; classes that can be used in your tests. The Mocklis solution consists of:
It's a bright spring morning... We're writing tests for a class called MySystem. It uses a service, somewhat surreptitiously named MyService to do its work, and the necessary functionality has been surfaced through an interface:
public interface IMyService { int ClientId { get; } string Echo(string text, TimeSpan timeout); }
The MySystem class we want to test has an IMyService parameter in its constructor, and we could pass it a real MyService instance. There are only two problems.
The solution of course is to create a mock - our own implementation of the IMyService interface - and pass that to the MySystem constructor. Mocklis not only helps to do this. It does it in a way that lets us fine-tune the behaviour of the Mock on a case-by-case basis. How? Read on.
You create an empty class implementing the interface(s) you need, and add a
[MocklisClass] attribute.
The Mocklis Mock Generator implements the interfaces explicitly
and provides 'Mocks' for adding behaviour.
[MocklisClass]
public class MockService : IMyService, IDisposable
{
public MockService()
{
ClientId = new PropertyMock(this, "MockService", "IMyService", "ClientId", "ClientId");
Echo = new FuncMethodMock<(string text, TimeSpan timeout), string>(this, "MockService", "IMyService", "Echo", "Echo");
Dispose = new ActionMethodMock(this, "MockService", "IDisposable", "Dispose", "Dispose");
}
public PropertyMock ClientId { get; }
int IMyService.ClientId => ClientId.Value;
public FuncMethodMock<(string text, TimeSpan timeout), string> Echo { get; }
string IMyService.Echo(string text, TimeSpan timeout) => Echo.Call((text, timeout));
public ActionMethodMock Dispose { get; }
void IDisposable.Dispose() => Dispose.Call();
}
Notice that every interface member is explicitly implemented and paired up with a public property.
When writing tests you add different types of behaviour to the public properties of your mock class instances.
// Create an instance of the mocklis class var mockService = new MockService(); // Return values or throw exceptions (first read returns 42, subsequent ones throw) mockService.ClientId .ReturnOnce(42) .Throw(() => new InvalidOperationException("connection lost")); // Record data during the test, and "Calculate" responses to function calls mockService.Echo .RecordBeforeCall(out var timeouts, p => p.timeout.TotalSeconds) .Func(p => $"You sent '{p.text}'!"); // Finally add the mock to the system we want to test var systemUnderTest = new MySystem(mockService);
This is of course just scratching the surface. Check the documentation for full details...
Mocklis was designed to make the most of Visual Studio Intellisense:
Nothing in the Mocklis Library is internal. If a helper class was used in a Mocklis built-in step, it's available to you when you write your own.
Mocklis generates source code. You can set breakpoints and use your existing debugging tools and skills to find out what's going on.
The Mocklis libraries are Source Linked debug builds. You can step straight into the Mocklis source code from your tests.
Mocklis has built-in logging. If you want to know how a step is interacted with, add a .Log() step just before it, and all interactions will be written to the console. Pass an ILogContext to the Log step to send data to other places such as Serilog or the xUnit ITestOutputHelper.
Thank you for reading! If you want to give Mocklis a try, find the Packages on Nuget, and some more in-depth documentation here. Then there's of course the GitHub project where you can get the source code as well as help and fixes for any issues that you might find.
Mocklis is released under the MIT license, the NuGet logo is CC BY Microsoft, the book icon is licensed from The Noun Project, the GitHub Mark is used in accordance with GitHub Logos and Usage, and the Mocklis logo is CC BY Esbjörn Redmo.