Moq (basics, part 1)

How to perform tests when classes or interfaces cannot be instantiated properly?

Let’s say you want to run a test, which has dependencies to something that is not available. You are programming a chess game. A certain constellation needs to be tested, but to get there you need to play the game for at least 20 minutes. Surely, you cannot afford waiting that long. The game has to start right away at the required constellation. This can only be done by simulating certain conditions like the piece positions. The game is still being programmed. It does not have load/save functionality yet.
Assume there is a class called “PositionOfTheQueen”. We need to override existing code without touching the class source code.

And here comes Moq into play.

With Moq you can instantiate classes or interfaces and change their behaviour externally. Method “GetPosition” would not return a calculated value, but a constant that we injected from a test class.

Reference to Inversion of Control
Wiki Mock object
Moq quickstart

In Visual Studio 2013 go to your “Project” menu. Then click “Manage NuGet Packages” and a new window will open. Enter “Moq” in the “Search Online” text box. There are many Moq packages out there. We select the first one from Daniel Cazzulino. It has more than 1.3 million downloads and seems to have gone through teething troubles a long time ago. Press the “Install” button.

Moq

The Moq library will be added to your References automatically. You don’t have to do anything. Have a quick look at your Solution Explorer:

SolutionExplorer

Here is the example source code. It is self-explanatory. I have added several tests to highlight issues.

  • Moq uses standard default values for anything that has not been Setup().
  • Methods with arguments are only defined when they were part of a Setup(). The argument has to be the same when the method is called. Otherwise the method will return the default value. You can define ranges for valid arguments with the class It.
  • You can only moq something when it is public virtual. ((“private” is possible but generally of no use.))
  • By using Moq you disregard program code. Classes behave like interfaces.
  • SetupProperty() can be used for properties that have setters and getters. Use SetupGet() or SetupSet() where this is not the case.
  • Set a setter of a property to see if a specific value will be set later on. Change the string in row t2.SetOnly = “xxx”; lMock.Verify(); to observe the behavior. An exception will be raised to tell that the expected value has not been set during any set operation.
using System;

namespace Moq {

  public interface ITestInterface {
    string GetValue();
    string GetValue2();
  } // interface

  public class TestClass {

    public virtual string GetValue() { return "Genuine as genuine can be"; }
    public virtual string GetValue2() { return GetValue(); }
    public virtual string GetValue3(int x) { return x.ToString(); }
    public virtual string GetValue4(string x) { return x; }
    public virtual string SetOrGet { get; set; }
    public virtual string GetOnly { get { return "Value 6"; } }
    public virtual string SetOnly { set { } }

  } // class

  class Program {

    static void Main(string[] args) {

      // unaltered class
      TestClass t1 = new TestClass();
      Console.WriteLine("unaltered class:");
      Console.WriteLine("GetValue() == " + t1.GetValue());
      Console.WriteLine("GetValue2() == " + t1.GetValue2());
      Console.WriteLine("GetValue3(99) == " + t1.GetValue3(99));

      // mocked class
      Mock<TestClass> lMock = new Mock<TestClass>();
      lMock.Setup(x => x.GetValue()).Returns("You have been mocked!");
      TestClass t2 = lMock.Object;
      Console.WriteLine("\nMocked class:");
      Console.WriteLine("GetValue() == " + t2.GetValue());
      Console.WriteLine("GetValue2() == " + t2.GetValue2());
      Console.WriteLine("GetValue3(99) == " + t2.GetValue3(99));
      lMock.Setup(x => x.GetValue2()).Returns("You have been mocked again!");
      lMock.Setup(x => x.GetValue3(99)).Returns("11");
      //lMock.Setup(x => x.GetValue2()).Returns(() => "You have been mocked again!"); 
      Console.WriteLine("GetValue2() == " + t2.GetValue2());
      Console.WriteLine("GetValue3(99) == " + t2.GetValue3(99));
      Console.WriteLine("GetValue3(22) == " + t2.GetValue3(22));
      Console.WriteLine("After defining the range 22 to 200:");
      lMock.Setup(x => x.GetValue3(It.IsInRange(22, 200, Range.Inclusive))).Returns("in range from 22 to 200");
      Console.WriteLine("GetValue3(22) == " + t2.GetValue3(22));
      Console.WriteLine("GetValue3(99) == " + t2.GetValue3(99));
      lMock.Setup(x => x.GetValue4(It.IsAny<string>())).Returns("no");
      Console.WriteLine("GetValue4(\"yes\") == " + t2.GetValue4("yes"));


      // mocked interface
      Console.WriteLine("\nMocked interface:");
      Mock<ITestInterface> lMock2 = new Mock<ITestInterface>();
      lMock2.Setup(x => x.GetValue()).Returns("Fictitious result from the happy hunting ground");
      ITestInterface t3 = lMock2.Object;
      Console.WriteLine("GetValue() == " + t3.GetValue());
      Console.WriteLine("GetValue2() == " + t3.GetValue2());
      Console.WriteLine("After diverting GetValue2():");
      lMock2.Setup(x => x.GetValue2()).Returns(() => t3.GetValue());
      Console.WriteLine("GetValue2() == " + t3.GetValue2());


      // callbacks
      Console.WriteLine("\nCallbacks:");
      Action lBefore = () => Console.WriteLine("before callback");
      Action lAfter = () => Console.WriteLine("after callback");
      lMock.Setup(x => x.GetValue()).Returns("return value\n").Callback(lAfter);
      Console.WriteLine(t2.GetValue());
      lMock.Setup(x => x.GetValue()).Callback(lBefore).Returns("return value\n");
      Console.WriteLine(t2.GetValue());
      lMock.Setup(x => x.GetValue()).Callback(lBefore).Returns("return value\n").Callback(lAfter);
      Console.WriteLine(t2.GetValue());


      // Properties
      Console.WriteLine("\nProperties:");
      lMock.SetupProperty(x => x.SetOrGet, "initial value");
      // lMock.SetupProperty(x => x.GetOnly, "initial value");  throws exception, because GetOnly is readonly
      // instead use:
      lMock.SetupGet(x => x.GetOnly).Returns("initial value");
      lMock.SetupSet(x => x.SetOnly = "xxx").Verifiable(); // expect a value
      t2.SetOnly = "xxx"; lMock.Verify();
      //t2.SetOnly = "yyy"; lMock.Verify(); // exception: expected value does not match if t2.SetOnly was NEVER set to "xxx"
      t2.SetOrGet = "altered value";
      Console.WriteLine("SetOrGet == " + t2.SetOrGet);

      Console.ReadLine();
    } //

  } // class
} // namespace

example output:
unaltered class:
GetValue() == Genuine as genuine can be
GetValue2() == Genuine as genuine can be
GetValue3(99) == 99

Mocked class:
GetValue() == You have been mocked!
GetValue2() ==
GetValue3(99) ==
GetValue2() == You have been mocked again!
GetValue3(99) == 11
GetValue3(22) ==
After defining the range 22 to 200:
GetValue3(22) == in range from 22 to 200
GetValue3(99) == in range from 22 to 200
GetValue4(“yes”) == no

Mocked interface:
GetValue() == Fictitious result from the happy hunting ground
GetValue2() ==
After diverting GetValue2():
GetValue2() == Fictitious result from the happy hunting ground

Callbacks:
after callback
return value

before callback
return value

before callback
after callback
return value

Properties:
SetOrGet == altered value

Advertisements

About Bastian M.K. Ohta

Happiness only real when shared.

Posted on May 20, 2014, in C#, Unit Testing and tagged , , , , , , , , , . Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: