Skip to main content

Unit Testing with Visual studio 2012 Fakes

With Visual studio 2012 Ultimate edition Microsoft has shipped new Faking framework which enable developer to isolate their unit tests from their environment. Now it’s time to understand them.
When we say external dependencies it may be of two types

1) Dependency to Interfaces or Abstract classes

Example
Customer Data Access Layer
public class CustomerDataAccessLayer
{
 publicbool Insert()
     {
  try
         {
   //Insert into database
   return true;
         }
  catch (Exception e)
         {
   return false;
         }
     }
}
Email library
public interface IEmailLibrary
{
 bool SendEmail();
}
 
public class EmailLibrary : IEmailLibrary
{
 public bool SendEmail()
     {
   //Send email code - > But right now email server is configure
  return true;
     }
}
Customer Middle Layer
public class CustomerMiddleLayer
{
 public string AddCustomer(string CustomerName,IEmailLibrary emailLibrary)
     {
  CustomerDataAccessLayer ObjLayer = new CustomerDataAccessLayer();
  ObjLayer.Insert();
 
  emailLibrary.SendEmail();
 
  return CustomerName;
     }
}
Unit Testing
If we follow simple Unit Testing steps for testing AddCustomer method in CustomerMiddleLayer class it won’t work out. Test will always fail. We even won’t be able to test the other logics in the AddCustomer method.
One way to achieve this is
  1. Create your own temporary class , inherit it from IEmailLibrary and use
  2. Use Mock frameworks like MOQ, Rhino MOCK etc. 
But I neither believe in
  1. Reinventing the wheel
  2. Nor asking other.
I mean, we can achieve same behavior with the help of Visual studio 2012
fakes.  
So let’s do it.
Step 1
In the Test Project expand reference tab, right click your assembly (MiddleLayer) and say generate Fake assembly.
Step 2
Import {YourNames}.Fakes in the top. In this case it will be
using MiddleLayer.Fakes;
Step 3
Create a new Test Method and use Stub version of IEmailLibrary instead of original Email library class.
[TestMethod]
public void TestAddMethodWithStubs()
{
 //Arrange
 CustomerMiddleLayer middleLayer = new CustomerMiddleLayer();
 string CustomerName = "Sukesh Marla";
 IEmailLibrary e = new StubIEmailLibrary
     {
  SendEmail=()=>true
     };
 
 //Act
 string returnCustomerName = middleLayer.AddCustomer(CustomerName, e);
 
 //Assert
 Assert.AreEqual<string>(CustomerName, returnCustomerName);
}

If you try to run this unit test it will always pass unless and until there are some error in some other partof Add Customer Function. It’s behaving so because instead of original EmailLibrary class we are passing stub version of it. In the stub version we have implemented SendEmail function which won’t do anything and return true directly.
Now let’s define stubs in technical words.
Stubs are simply Concrete Implementation of interfaces and abstract classes which you can pass across. Using lambda expression we provide method implementations to it.

2) Dependency to concrete classes

Customer Data Access Layer
(Same as above)
Email library
public class EmailLibrary 
{
 public bool SendEmail()
     {
   //Send email code - > But right now email server is configure        
  return true;
     }
}
Customer Middle Layer
public class CustomerMiddleLayer
{
 public string AddCustomer(string CustomerName)
     {
  CustomerDataAccessLayer ObjLayer = new CustomerDataAccessLayer();
  ObjLayer.Insert();
 
                EmailLibrary emailLibrary= new EmailLibrary();
  emailLibrary.SendEmail();
 
  return CustomerName;
     }
}
Unit Testing
We don’t have interfaces now, so stubs won’t work now, but we can use Shims. Shims are runtime method interceptors. They are more powerful than stubs. Using them we can add our own implementation to any method or property belonging to any available class in our own assembly or .net base class library.
Using Shims is considered as bad practice because you are using shims because your code is not following standards otherwise it would have allowed you generate stubs (not true always). Many time we have not left with any choice that using Shims.
Step 1 and Step 2 are going to be just same as above.
Step 3
Create a new Test Method and create Shims context inside it.
[TestMethod]
public void TestMethodWithShims()
{
 //Arrange
 CustomerMiddleLayer middleLayer = new CustomerMiddleLayer();
 string CustomerName = "Sukesh Marla";
 
 //Act
 string returnCustomerName = null;
 
 using (ShimsContext.Create())
     {
  ShimEmailLibrary.AllInstances.SendEmail = (@this) =>{ return true; };
  returnCustomerName=middleLayer.AddCustomer(CustomerName);
     }

 //Assert
 Assert.AreEqual<string>(CustomerName, returnCustomerName);
} 
While using shims its must to define scoping region where call will be replaced with the help of ShimsContext.Create() block. Within the defined region every call to SendEmail function get replaced with call to SendEmail functionwhich we have defined (where we are doing nothing just returning true).

Shims for overriding environmental dependencies

Now let’s see a small demonstration where we will try to use environmental dependencies like DateTime.Now
First let’s create SUT – System under Test – Code which need to be tested
public class YearUtilities
{
 publicbool IsTodayLastDateOfYear()
     {
  DateTime TodayDate = DateTime.Now;
  if (TodayDate.Day == 31 && TodayDate.Month == 12)
         {
   return true;
         }
  else
         {
   return false;
         }
     }
}
Now let’s create Test Methods using normal way.
[TestMethod]
public void TestForLastDay()
{
 //Arrange
 YearUtilities yearUtilities = new YearUtilities();
 
 //Act
 bool CurrenrResult = yearUtilities.IsTodayLastDateOfYear();
 
 //Assert
 Assert.AreEqual<bool>(true, CurrenrResult);
}
 
[TestMethod]
public void TestForNotLastDay()
{
 //Arrange
 YearUtilities yearUtilities = new YearUtilities();
 
 //Act
 bool CurrenrResult = yearUtilities.IsTodayLastDateOfYear();
 
 //Assert
 Assert.AreEqual<bool>(false, CurrenrResult);
}
When you try to run this test methods, first test method will pass only on last day of year and Second method will pass all days except last day of year. This is not feasible in real life projects. We cannot wait till last day of year and then go and test our code.
Let’s rewrite above Test methods using Shims
Step 1
In the Test Project expand reference tab, right click assembly called System and say generate Fake assembly.
Step 2
Import namespace at the top as using System.Fakes;
Step 3
Write Test method as follows
[TestMethod]
public void TestForLastDay()
{
 //Arrange
 YearUtilities yearUtilities = new YearUtilities();
 
 //Act
 bool CurrenrResult = false;
 using (ShimsContext.Create())
     {
  ShimDateTime.NowGet = () =>new DateTime(2012, 12,31);
  CurrenrResult =yearUtilities.IsTodayLastDateOfYear();            
     }
 
 //Assert
 Assert.AreEqual<bool>(true, CurrenrResult);
}
 
[TestMethod]
public void TestForNotLastDay()
{
 //Arrange
 YearUtilities yearUtilities = new YearUtilities();
 
 //Act
 bool CurrenrResult = false;
 using (ShimsContext.Create())
     {
  ShimDateTime.NowGet = () =>new DateTime(2012, 12,15);
  CurrenrResult = yearUtilities.IsTodayLastDateOfYear();
     }
 
 //Assert
 Assert.AreEqual<bool>(false, CurrenrResult);
}
Now when Test Methods are executed, DateTime.Now will return either 15 December 2012 or 31 December 2012 respectively. That means you can test your code throughout the year, anytime and anywhere.

At last:


Visual studio Fakes are really very powerful feature. When it comes to good practice stubs are at top but in some cases we won’t left with any choice than using shims.

Popular posts from this blog

Creating package in Oracle Database using Toad For Oracle

What are Packages in Oracle Database A package is  a group   of procedures, functions,  variables   and  SQL statements   created as a single unit. It is used to store together related objects. A package has two parts, Package  Specification  and Package Body.

Resolving 'Setup Account Privileges' error while installing SQL Server

A new installation of Microsoft SQL Server 2012 or Microsoft SQL Server 2008 R2 fails You see the following error message when you try to install a new instance of SQL Server 2012 or SQL Server 2008 R2: Rule "Setup account privileges" failed.

Creating Oracle stored Procedures using TOAD for Oracle

In a database management system, a  stored procedure  is a set of Structured Query Language (SQL) statements with an assigned name that's stored in the database in compiled form so that it can be shared by a number of programs. The use of  stored procedures  can be helpful in controlling  access to data, preserving  data integrity  and  improving  productivity.