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.
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:
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) == 99Mocked 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”) == noMocked interface:
GetValue() == Fictitious result from the happy hunting ground
GetValue2() ==
After diverting GetValue2():
GetValue2() == Fictitious result from the happy hunting groundCallbacks:
after callback
return valuebefore callback
return valuebefore callback
after callback
return valueProperties:
SetOrGet == altered value
Posted on May 20, 2014, in C#, Unit Testing and tagged C#, C-sharp, Dependency Injection, Inversion of Control, Mock Object, Moq, programming, Source code, testing, Unit Testing. Bookmark the permalink. Leave a comment.
Leave a comment
Comments 0