Click here to Skip to main content
15,881,600 members
Articles / Programming Languages / C#

Examples of Mock Usages

Rate me:
Please Sign up or sign in to vote.
4.74/5 (6 votes)
11 May 2016CPOL4 min read 12K   85   12   1
Examples of Mock usages

Introduction

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

In the market, there exist 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 no separation between stubs and mocks. Or if to speak more formally, there is no separation for state verification and behavior verification. And despite the 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, we will switch to behavior verification.

State Verification

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

C#
public interface ILoggerSomeDependency
{
 	string GetApplicationDirectory();
	string GetDirectoryForDependencyByLoggerName(string loggerName);
	string GetLoggerInstance{get;}
} 
  1. Stub of method GetApplicationDirectory:
    C#
    //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:
    C#
    // 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 on the argument:
    C#
    // 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:
    C#
    // 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 the help of “mock functional specification” (was born in v4):
    C#
    // 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):
    C#
    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 the following class and interface:

C#
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):
    C#
    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:
    C#
    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):
    C#
    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 the following methods of class Times: AtLeast(int), AtMost(int), Exactly, Between and others.

  4. Checking behavior with the help of method Verify (you can use other convenient, for cases if you need to check few assumptions):
    C#
    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 the 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 the 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.
    C#
    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 the 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:

C#
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:

    C#
    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 its method Write should call methods of those two dependencies.

    For example, like this:

    C#
    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:

    C#
    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 sometimes it's easier to use LINQ-based syntax for one part of methods and use Setup methods for other part of methods:

C#
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 a topic for another article.

If you are confused in tests, I've attached an implementation of Interfaces and some classes.

This article was originally posted at http://blog.zaletskyy.com/one-more-summary-of-moq-library

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Kensium
Ukraine Ukraine
Hi,
I'm Acumatica ERP Solutions architect at Kensium. Besides ERP programming my area of interests includes Neural Networks, Machine Learning, Statistics and of course performance optimization.
Here is my blog: http://blog.zaletskyy.com

Comments and Discussions

 
GeneralMy vote of 5 Pin
joyhen12312311-May-16 21:19
joyhen12312311-May-16 21:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.