Introduction
When it comes to 'Unit Testing' your code - you will want to test a small code base at a time (i.e. each method within your respective classes). This will lead to greater stability within your overall project, if you know that each method does what it is expected. When testing the working of a method, you will want to exclude external calls to databases, third party DLLs or your own services, so that you can better 'Black Box Test' your application. To exclude these external resources from your code and be able to replace these method call returns with your own method call returns - you will need to mock your tests. There are a number of very well written mocks available - but MOQ is one that is easy to get up and running quickly - which is a huge bonus when a developer has to unit test their code.
Background
What is a Mock
Mock objects are instantiated objects that mimic the behavior of real objects in a controlled environment – thus supplying an informed (expected) result.
Why Mock
It is best to design libraries to have a minimal set of dependencies, but sometimes this is not practical, especially when the library has not been designed with testability in mind. When unit testing libraries with a complex set of dependencies, these dependencies may require difficult or time-consuming setup procedures which are detrimental to the test itself. It will be very common that the code that you are unit testing will depend on a dependency that hasn't been fully tested yet or eventfully designed. But that shouldn't stop a developer from being able to test their new procedural code – thus you will mock up the return from this (not yet tested) dependency and test that your code behaves as expected. Mocking also gives you a better code coverage - using tools like Ncover can greatly increase your teams productivity, in that you can see what code paths have been tested and which paths still need more testing – thus mocks can greatly enhance your code coverage by letting you implement paths that would normally of needed more setup (calling services or populating a database table with certain data) to perform your test.
Mocks become (necessary) advantageous when an method/object being unit tested has the following characteristics:
- Has states that are difficult to create or reproduce (e.g. a network error, database server down)
- Is slow (e.g. Make multiple calls to multiple services, which would have to be initialized before the test)
- Does not yet exist or may change behavior
- Would have to include information and methods exclusively for testing purposes (and not for its actual task)
Difference Between A Mock Test and an Integration Test
Basically, with an integration test, you are performing an end-to-end test of your system to see that it functions as a whole system as expected. But with mocking, you are looking to see if your smaller snippet of code (function) works as expected. So, in saying that, an integration test is made up of many smaller units of code (which you will have already mocked individually).
Using the Code
Visual Studio Project Structure
In Fig 1, you can see the structure I have created for the solution. I have a class definition, a couple of class libraries (the MainApp
will be equivalent to MainContext
class in your application). A group of tests projects and finally a WCF service.
Fig. 1
Fig 2 shows an expanded solution. The idea is that the 'MoqDllTests
' project will mock the calls to the DLLs (DatabaseLib
and FileLib
) methods that are used in the 'MainApp
' project. The second test project, 'MoqServiceTests
', will mock calls to the WCF service 'MoqService
', from calls within the class 'ViewModel
', inside this test project (this class 'ViewModel
' would be like a Context
class).
Fig. 2
Pet Class
The Pet
class below - is just a 'plain old class object' (POCO), with some private
properties, constructors, enumerations and setters & getter. This class is used for passing information back from the (external) services or class libraries - thus their contents will be mocked in certain circumstances.
[Serializable]
public class Pet
{
public Pet(string name, int age, AnimalType typeOfAnimal, List<Food> canEat)
{
this.Age = age;
this.CanEat = canEat;
this.TypeOfAnimal = typeOfAnimal;
this.Name = name;
}
public Pet() { }
public string Name { set; get; }
public int Age { set; get; }
public AnimalType TypeOfAnimal { set; get; }
public List<Food> CanEat { set; get; }
[Serializable]
public enum Food
{
Hay,
Chum,
Milk
}
[Serializable]
public enum AnimalType
{
Dog,
Cat,
Horse,
Rabbit
}
}
Main Class
Below is the code for the main application - maybe in your case, the start page, for example. I basically want to test these methods below function properly - but I do not want to test the methods that they call, if they are outside the scope of this test (i.e., making a call to a database or the DLLs - which they all do in some form or another.)
public class Context
{
#region Class Variables
public IFileController MyFile { get; set; }
public IDatabaseController MyDatabase { get; set; }
public IPetsController MyPetService { get; set; }
#endregion
#region Constructors
public Context(IFileController fileService, IDatabaseController databaseService,
IPetsController petService)
{
this.MyFile = fileService;
this.MyDatabase = databaseService;
this.MyPetService = petService;
}
public Context()
{
this.MyFile = new FileController();
this.MyDatabase = new DatabaseController();
this.MyPetService = new PetsService.PetsControllerClient();
}
#endregion
#region Class Methods
public int DoubleNumberOfKennelsInDatabase()
{
return this.MyDatabase.NumberOfKennelsInDatabase() * 2;
}
public int TrebleNumberOfKennelsOnFile()
{
return this.MyFile.NumberOfKennelsOnFile() * 3;
}
public int QuadrupalNumberOfKennelsOnWcfService()
{
return this.MyPetService.NumberOfDogs() * 4;
}
#endregion
}
Below is the declaration for Interface of the database access layer and the implementation of the database layer itself. I have only two simple methods that I use, which are used by the (Context
) class above. Notice that I overload the constructor to be a normal empty parameter and to also take references to external DLLs or references, this constructor is the main reason why I am able to mock the methods inside this class - meaning that I am able to inject mock references into the database layer class, but will not interfere with the workings of the methods in the layer itself.
namespace DatabaseLib
{
public interface IDatabaseController
{
int NumberOfKennelsInDatabase();
DateTime ClosingTimeKennels();
}
}
namespace DatabaseLib
{
public class DatabaseController : IDatabaseController
{
public IPetsController MyPetService { get; set; }
public DatabaseController() { }
public DatabaseController(IPetsController petService) {
this.MyPetService = petService; }
public int NumberOfKennelsInDatabase()
{
return 10;
}
public DateTime ClosingTimeKennels()
{
return MyPetService.GetCurrentDateTime().AddHours(1);
}
}
}
Unit Tests And Setting Up Mocking Object
The code snippet below shows how I am setting up the mock instances within my test class. I plan to mock the IDatabase
, IFile
and the MoqService
objects. So that when certain (mocked) methods are called, they will not go to the database, file system or web service but just return what I have instructed them to return.
Notice that inside the Init()
method, I create some dummy data (Pet
class) that will account for the expected data when returned by the mocked methods. This is 'Black Box Testing', comparing what was returned to what was expected.
#region Class Variables
Mock<IDatabaseController> moqDB;
Mock<IFileController> moqFile;
Mock<ProjectCode.PetsService.IPetsController> petService;
Context context;
List<Pets.Pet> lstPets;
#endregion
#region Constructor
public ContextTests(){}
#endregion
#region Setup
[TestFixtureSetUp]
public void Init()
{
moqDB = new Mock<IDatabaseController>();
moqFile = new Mock<IFileController>();
petService = new Mock<ProjectCode.PetsService.IPetsController>();
context = new Context(moqFile.Object, moqDB.Object, petService.Object);
lstPets = new List<Pets.Pet>();
var pet = new Mock<Pets.Pet>(MockBehavior.Strict).SetupAllProperties();
var petStub = pet.Object;
petStub.Age = 20;
petStub.CanEat = new List<Pets.Pet.Food>();
petStub.CanEat.Add(Pets.Pet.Food.Milk);
petStub.Name = "TopCat";
petStub.TypeOfAnimal = Pets.Pet.AnimalType.Cat;
lstPets.Add(petStub);
petStub.Age = 10;
petStub.CanEat.Clear();
petStub.CanEat.Add(Pets.Pet.Food.Chum);
petStub.CanEat.Add(Pets.Pet.Food.Milk);
petStub.Name = "TopDog";
petStub.TypeOfAnimal = Pets.Pet.AnimalType.Dog;
lstPets.Add(petStub);
}
#endregion
A Mocked Call To A Class Library
I want to make sure the database class method 'NumberOfKennelsInDatabase()
' will return a certain number when it is executed by the method 'DoubleNumberOfKennels()
' in the 'MainContext
' class. In the example code, I am telling the method 'NumberOfKennelsInDatabase()
' to return 25
whenever it is called. All the 'DoubleNumberOfKennels()
' does is double the returned value, thus I know what to Assert against the value coming back from 'DoubleNumberOfKennels()
'.
Remember, we are testing the code in the 'Context
' class, thus we are mocking the code in the database class (one layer extracted from it).
[Test(Description = "Mocking a Context class method that makes a db call operation.")]
public void TestMockDBCall()
{
moqDB.Setup(db => db.NumberOfKennelsInDatabase()).Returns(25);
int retValue = context.DoubleNumberOfKennelsInDatabase();
Assert.IsTrue(retValue == 50.0);
}
Mocking An Expected Exception
A developer will need to mock certain known exceptions and test how their code handles such exceptions. Thus, you are able to throw a mocked exception back to your calling class and thus test how your code handles the result from the mock.
[Test(Description = "Test for an expected thrown exception")]
[ExpectedException(typeof(ArgumentException))]
public void TestThrownExceptionNumberOfDogs()
{
const string exceptionMessage = "Non-Initialised Object On Server.";
Mock<IPetsController> petServiceTests = new Mock<IPetsController>();
petServiceTests.Setup<int>(method => method.NumberOfDogs()).Throws(
new ArgumentException(exceptionMessage));
IPetsController value = petServiceTests.Object;
int returns = value.NumberOfDogs();
#region Alternative code
#endregion
}
Mocking Synchronized Calls (MoqServiceTests project)
In the second test project, I perform the synchronized and asynchronized tests, in the code below, there is an asynchronized method and its corresponding completed method. I want to test that I can call each individually, and then that I can call the 'Begin
' method and test what was returned in the 'End
' method.
To so this, I have a class create a new Context
class called 'ViewModel
'. This class will be my main class that calls the service methods below. So, I want to test these calling methods in 'ViewModel
' and mock the service calls.
private IDatabaseController iDatabaseController;
public PetsController() { iDatabaseController = new DatabaseController(); }
public PetsController(IDatabaseController databaseService) {
iDatabaseController = databaseService; }
#region Async. Method
public IAsyncResult BeginGetAllPetsByAge(int age, AsyncCallback callback,
object asyncState)
{
Pet pet = new Pet();
List<Pets.Pet> listPets = new List<Pets.Pet>();
pet.Age = 10;
pet.CanEat.Add(Pet.Food.Hay);
pet.Name = "Jumper";
pet.TypeOfAnimal = Pet.AnimalType.Horse;
listPets.Add(pet);
return new CompletedAsyncResult<List<Pets.Pet>>(listPets);
}
public List<Pets.Pet> EndGetAllPetsByAge(IAsyncResult r)
{
CompletedAsyncResult<List<Pets.Pet>> result =
r as CompletedAsyncResult<List<Pets.Pet>>;
return result.Data;
}
[Test]
public void TestBeginAsync()
{
AsyncCallback callback = new AsyncCallback(CompletePets);
Mock<IAsyncResult> mockAsyncResult = new Mock<IAsyncResult>();
IAsyncResult expectedAasyncResult;
Mock<IPetsController> petServiceTests = new Mock<IPetsController>();
petServiceTests.Setup(async => async.BeginGetAllPetsByAge(It.IsAny<int>(),
It.IsAny<AsyncCallback>(),
It.IsAny<object>())).Returns(mockAsyncResult.Object);
IPetsController value = petServiceTests.Object;
expectedAasyncResult = value.BeginGetAllPetsByAge(10, callback, new object());
Assert.IsTrue(expectedAasyncResult == mockAsyncResult.Object);
}
[Test]
public void TestEndAsync()
{
List<Pets.Pet> expectedResult = new List<Pets.Pet>();
AsyncCallback callback = new AsyncCallback(CompletePets);
Mock<IAsyncResult> mockAsyncResult = new Mock<IAsyncResult>();
Mock<IPetsController> petServiceTests = new Mock<IPetsController>();
petServiceTests.Setup(async => async.EndGetAllPetsByAge(
It.IsAny<IAsyncResult>())).Returns(this.lstPets);
IPetsController value = petServiceTests.Object;
expectedResult = value.EndGetAllPetsByAge(mockAsyncResult.Object);
Assert.IsTrue(this.lstPets == expectedResult);
}
Mocking Asynchronized Calls
Below, I am performing an asynchronized test, in that I am mocking the 'Begin
' and the 'End
' method calls in the WCF Service. I am calling the method 'ProcessAsync(int)
' in the 'ViewModel
' class that performs the initial call 'Begin
' to the service. Then, I am asserting that the value I expect the completed event to pass back was actually passed back.
[Test]
public void TestAsyncCompleted()
{
AsyncCallback callback = null;
IAsyncResult ar = new Mock<IAsyncResult>().Object;
var wcfService = new Mock<IPetsController>();
wcfService.Setup(async => async.BeginGetAllPetsByAge(It.IsAny<int>(),
It.IsAny<AsyncCallback>(),null))
.Callback((int age, AsyncCallback cb, object state) => callback = cb)
.Returns(ar);
wcfService.Setup(async => async.EndGetAllPetsByAge(It.IsAny<IAsyncResult>()))
.Returns(this.lstPets);
var sut = new ViewModel(wcfService.Object);
sut.ProcessAsync(10);
callback(ar);
Assert.AreEqual(this.lstPets, sut.ListOfPets);
}
Mocking Database Call in Asynchronized Calls
Below, I inject a mocked database layer object into the service constructor, mocking a particular database call method 'NumberOfKennelsInDatabase()
' that is used by the service method 'BeginServiceCallsDB
'. The asynchronized call below is a little different to the one used above in that I am testing the IAsyncResult
that comes back from the asynchronized call.
[Test]
public void TestAsyncMethodAndMockDBCallInService()
{
Mock<DatabaseLib.IDatabaseController> MockDB =
new Mock<DatabaseLib.IDatabaseController>();
MockDB.Setup(meth => meth.NumberOfKennelsInDatabase()).Returns(2);
AsyncCallback callback = new AsyncCallback(CompletePets);
IAsyncResult expectedAasyncResult;
IPetsController petServiceTests = new PetsController(MockDB.Object);
expectedAasyncResult = petServiceTests.BeginServiceCallsDB(callback,
new object());
Assert.IsTrue(((Pets.CompletedAsyncResult<int>)
(expectedAasyncResult)).Data == 4);
}
Useful Links
References Used Within the Project
NUnit Results