One more summary of Moq library

Examples of Mock usages

Mock - is a simple and lightweight isolation framework, which is built on the basis of anonymous methods and expression trees. To create them it uses code generation, thus allowing to mock interfaces, virtual methods (and even protected methods) and does not allow to mock non-virtual and static methods.

NOTE

At market exists only two frameworks that allow to mock anything. These are TypeMockIsolator and Microsoft Fakes, available in Visual Studio 2012 and higher. These frameworks, unlike Mock ( which uses code generation) use CLR Profiling API, allowing to mock any method even for static, virtual and private methods. IMHO they are good for testing legacy code which is hard or impossible to refactor in one bunch.

In Mock there is not separation between stubs and mocks. Or if to speak more formally there is no separation for state verification and behavior verification. And despite fact that it not always easy to draw the line between them, quite often the same element can be in both roles. We will consider examples from simple to complex. Initially we will consider state verification and later will switch to behavior verification.

State verification.

As example we will consider set of unit tests for the following interface:

public interface ILoggerSomeDependency
{
 string GetApplicationDirectory();
ing GetDirectoryForDependencyByLoggerName(string loggerName);
ring GetLoggerInstance{get;}
}

 

1. Stub of method GetApplicationDirectory:

//Mock.Of returns dependency itself proxy object ,not mock object
//Following code means, that as result of calling GetApplicationDirectory()
//we will receive "C:\\Windows\\Fenestra"
IloggerSomeDependency loggerDependency = 
Mock.Of<ILoggerSomeDependency>(d=>d.GetApplicationDirectory()=="C:\\Windows\\Fenestra");
var currentDirectory = loggerDependency.GetApplicationDirectory(); 
Assert.That(currentDirectory,Is.EqualTo("C:\\Windows\\Fenestra"));



2. Stub of method GetDirectoryForDependencyByLoggerName, always returns the same result:

// For any argument of method GetDirectoryForDependencyByLoggerName return "C:\\Merced".
ILoggerSomeDependency loggerDependency = Mock.Of<ILoggerSomeDependency>(ld => ld.GetDirectoryForDependencyByLoggerName(It.IsAny<string>()) == "C:\\Merced"); 
string directory = loggerDependency.GetDirectoryForDependencyByLoggerName("anything");
Assert.That(directory, Is.EqualTo("C:\\Merced"));

3. Stub of method GetDirrectoryByLoggerName, returns result depending from argument

// Initialize stub with dependency from passed argument 
// into method GetDirrectoryByLoggerName
// Code is similar to stub 
// public string GetDirectoryForDependencyByLoggerName(string s) { return "C:\\" + s; }
Mock<ILoggerSomeDependency> stub = new Mock<ILoggerSomeDependency>();
 
stub.Setup(ld => ld.GetDirectoryForDependencyByLoggerName(It.IsAny<string>()))
         .Returns<string>(name => "C:\\" + name);
 
string loggerName = "AnyLogger";
ILoggerSomeDependency logger = stub.Object;
string directory = logger.GetDirectoryForDependencyByLoggerName(loggerName);
 
Assert.That(directory, Is.EqualTo("C:\\" + loggerName));

4. Stub of property GetLoggerInstance:

// Property GetLoggerInstance of our stub will return pointed value
ILoggerSomeDependency logger = Mock.Of<ILoggerSomeDependency>(
    d => d.GetLoggerInstance == "GetLoggerInstance");
 
string GetLoggerInstance = logger.GetLoggerInstance;
 
Assert.That(GetLoggerInstance, Is.EqualTo("GetLoggerInstance"));



5. Setting behavior of few methods with one expression with help of mock functional specification” (was born in v4): 

// Join stubs of different methods with help of logical and
 
ILoggerSomeDependency logger =
    Mock.Of<ILoggerSomeDependency>(
        d => d.GetApplicationDirectory() == "C:\\Windows\\Fenestra" &&
                d.GetLoggerInstance == "GetLoggerInstance" &&
                d.GetDirectoryForDependencyByLoggerName(It.IsAny<string>()) == "C:\\Windows\\Temp");
 
Assert.That(logger.GetApplicationDirectory(), Is.EqualTo("C:\\Windows\\Fenestra"));
Assert.That(logger.GetLoggerInstance, Is.EqualTo("GetLoggerInstance"));
Assert.That(logger.GetDirectoryForDependencyByLoggerName("CustomLogger"), Is.EqualTo("C:\\Windows\\Temp"));

6. Configuring of behavior of few methods with usage of method Setup (ancient or v3 syntax):

var stub = new Mock<ILoggerSomeDependency>();
stub.Setup(ld => ld.GetApplicationDirectory()).Returns("C:\\Windows\\Fenestra");
stub.Setup(ld => ld.GetDirectoryForDependencyByLoggerName(It.IsAny<string>())).Returns("C:\\Windows\\Temp");
stub.SetupGet(ld => ld.GetLoggerInstance).Returns("GetLoggerInstance");
 
ILoggerSomeDependency logger = stub.Object;
 
Assert.That(logger.GetApplicationDirectory(), Is.EqualTo("C:\\Windows\\Fenestra"));
Assert.That(logger.GetLoggerInstance, Is.EqualTo("GetLoggerInstance"));
Assert.That(logger.GetDirectoryForDependencyByLoggerName("CustomLogger"), Is.EqualTo("C:\\Windows\\Temp"));



Note

As it was already mentioned Mock doesn't differ between mocks and stubs, but for us it will be easier to distinguish syntax of initialization of stubs. Mock functional specification syntax may be used for testing state condition ( i.e. for stubs ) and can't be used for configuring behavior. On the other hand initialization of stubs with method Setup can be more cumbersome and not always easy to grasp what we want to check behavior or state.

Behavior verification

For testing behavior we will use following class and interface:


public interface ILogSaver
{
    string GetLogger();
    void SetLogger(string logger);
    void Write(string message);
}
 
public class Logger
{
    private readonly ILogSaver _logSaver;
 
    public Logger(ILogSaver logWriter)
    {
        _logSaver = logWriter;
    }
    public void WriteLine(string message)
    {
        _logSaver.Write(message);
    }
}

1. Checking of calling of method ILogSaver.Write with object of class Logger (with any argument):

var mock = new Mock<ILogSaver>();
var logger = new Logger(mock.Object);
 
logger.WriteLine("Greeting by logger!");
 
// Check that method Write was called of our Mock with any argument
mock.Verify(lw => lw.Write(It.IsAny<string>()));

2. Checking of calling method ILogSaver.Write with configured arguments:

var mock = new Mock<ILogSaver>();
mock.Verify(lw => lw.Write("Greeting by logger!"));



3. Checking that method ILogSaver.Write was called only once (not more or less):

var mock = new Mock<ILogSaver>();
mock.Verify(lw => lw.Write(It.IsAny<string>()), Times.Once());



Note.
There are many options of checking how many times some dependency was called. For this purpose you can use following methods of class Times: AtLeast(int), AtMost(int), Exactly, Between and others.

4. Checking behavior with help of method Verify (you can use other convenient, for cases if you need to check few assumptions):

var mock = new Mock<ILogSaver>();
mock.Setup(lw => lw.Write(It.IsAny<string>()));
 
var logger = new Logger(mock.Object);
logger.WriteLine("Greeting by logger!");
 
// We didn't pass into method Verify any additional parameters.
// It means that method Verify will use expectations 
// configured with help of mock.Setup
mock.Verify();



5. Checking of few callings with help of method Verify().
In some situations it is convenient to use few methods of Verify for checking of some callings. Instead of this you can use mock-object and configure expected behavior with help of Setup and check those assumptions with calling of one method Verify(). This technique can be convenient for repeating of testing of Mock objects, created in configurations of method Setup test.

var mock = new Mock<ILogSaver>();
mock.Setup(lw => lw.Write(It.IsAny<string>()));
mock.Setup(lw => lw.SetLogger(It.IsAny<string>()));
 
var logger = new Logger(mock.Object);
logger.WriteLine("Greeting by logger!");
 
mock.Verify();

Lyric notes or strict vs loose model


Mock supports two models of checking behavior: strict and loose. By default loose model is used, which means that Class Under Test or CUT during execution in section Act can call any methods of dependencies and we are not obliged to point them all. As in previous example method logger.WriteLine calls two methods of interface ILogSaver: method Write and SetLogger. In case of usage MockBehavior.Strict method Verify will fail, if we will not point clearly, which methods of dependencies will be called:

var mock = new Mock<ILogSaver>(MockBehavior.Strict);
// if to comment any of the next lines
// then mock.Verify() will fail with exception
mock.Setup(lw => lw.Write(It.IsAny<string>()));
mock.Setup(lw => lw.SetLogger(It.IsAny<string>()));
 
var logger = new Logger(mock.Object);
logger.WriteLine("Greeting by logger!");
 
mock.Verify();

Usage of MockRepository



Class MockRepository provides one more syntax for creating stubs and what is more important allows to preserve few mock objects and check complex behavior with calling of one method.


1. Usage MockRepository.Of for creating stubs

Syntax is analogical to usage Mock.Of, but allows to set behavior of different methods not via operator && but with usage of few methods Where:


var repository = new MockRepository(MockBehavior.Default);
 
ILoggerSomeDependency logger = repository.Of<ILoggerSomeDependency>()
    .Where(ld => ld.GetLoggerInstance == "GetLoggerInstance")
    .Where(ld => ld.GetApplicationDirectory() == "C:\\Windows\\Fenestra")
    .Where(ld => ld.GetDirectoryForDependencyByLoggerName(It.IsAny<string>()) == "C:\\Windows\\Temp")
    .First();
 
Assert.That(logger.GetApplicationDirectory(), Is.EqualTo("C:\\Windows\\Fenestra"));
Assert.That(logger.GetLoggerInstance, Is.EqualTo("GetLoggerInstance"));
Assert.That(logger.GetDirectoryForDependencyByLoggerName("CustomLogger"), Is.EqualTo("C:\\Windows\\Temp"));



2. Usage of MockRepository for setting behavior of few mock objects. Suppose you have more complicated class WizzLogger, which needs two more dependencies: ILogSaver and ILogMailer. Our testing class with calling it's method Write should call methods of those two dependencies.

For example like this:

public interface ILogSaver
{
    string GetLogger();
    void SetLogger(string logger);
    void Write(string message);
}
 
public interface ILogMailer
{
    void Send(MailMessage mailMessage);
}
 
public class WizzLogger
{
    private ILogMailer mailer;
    private ILogSaver saver;
 
    public WizzLogger(ILogSaver s, ILogMailer m)
    {
        mailer = m;
        saver = s;
    }
    public void Send(MailMessage mailMessage) { }
 
    public void WriteLine(string message)
    {
        mailer.Send(new MailMessage());
        saver.Write(message);
    }
}

then in your test you can write like this:

var repo = new MockRepository(MockBehavior.Default);
var logWriterMock = repo.Create<ILogSaver>();
logWriterMock.Setup(lw => lw.Write(It.IsAny<string>()));
 
var logMailerMock = repo.Create<ILogMailer>();
logMailerMock.Setup(lm => lm.Send(It.IsAny<MailMessage>()));
 
var WizzLogger = new WizzLogger(logWriterMock.Object, logMailerMock.Object);
 
WizzLogger.WriteLine("Hello, Logger");
 
repo.Verify();

Other ways
In some cases it can be useful to get Mock object itself according to interface ( get Mock<ISomething> of interface ISomething ). For example functional syntax of stubs initialization returns not Mock object, but required interface immediately. This can be convenient for testing pair of simple methods, but not convenient if you also need to check behavior or configure method, which gives different results for different parameters. As outcome sometime it's easier to use LINQ-based syntac for one part of methods and use Setup methods for other part of methods:

ILoggerSomeDependency logger = Mock.Of<ILoggerSomeDependency>(ld => ld.GetApplicationDirectory() == "C:\\Windows\\Fenestra"
        && ld.GetLoggerInstance == "GetLoggerInstance");
 
// Set more complicated behavior of method GetDirectoryForDependencyByLoggerName
// for returning different results depending from argument
Mock.Get(logger)
    .Setup(ld => ld.GetDirectoryForDependencyByLoggerName(It.IsAny<string>()))
    .Returns<string>(loggerName => "C:\\" + loggerName);
 
Assert.That(logger.GetApplicationDirectory(), Is.EqualTo("C:\\Windows\\Fenestra"));
Assert.That(logger.GetLoggerInstance, Is.EqualTo("GetLoggerInstance"));
Assert.That(logger.GetDirectoryForDependencyByLoggerName("Foo"), Is.EqualTo("C:\\Merced"));
Assert.That(logger.GetDirectoryForDependencyByLoggerName("Itanium"), Is.EqualTo("C:\\Itanium"));

Besides this Mock allows to check behavior of protected methods, test events and contains other features. But that can be topic for another article.

No Comments

Add a Comment