Introduction
In this article we will make a deep dive into VS 2012 Fakes.
In order to understand Fakes in VS 2012 properly, you must understand Unit Testing first. That’s why it will be better if I speak about it first.
I have divided this article into three sections.
In the first section we will understand basics of unit testing
- What is Unit Testing?
- What are its benefits?
- A simple example of unit testing using Visual studio.
In the second section, we will make a deep dive into Unit Testing
- What are the properties of good Unit Test?
- What is mean by Untestable code?
In the last section we will have talking on VS 2012 Fakes.
- What are Stubs in VS 2012?
- What problem Stubs Solve?
- What are Shims in VS 2012?
- What problem Shims Solve?
| |
I will strongly recommend to you to choose the appropriate section as per your understanding level and then proceed.
Unit Testing
What is Unit Testing?
Unit testing means “Testing smallest logic that we can test isolating from other”.
Bit technical definition, let’s try to make it simple.
Every system/application consist of one or more modules each one of which will in turn contain sub modules. For building those sub modules we create many classes containing functions/methods which perform specific actions.
- In Unit Testing we write code (test methods) which will test those functions on behalf of us. We write test method for every function in our application which has some important logic.When function (piece of code block) won’t satisfy our requirement, unit test will fail.
- We write and conduct unit tests in development phase.
- In Unit Testing one test will look into the only one unit (requirement – every smallest requirement) of software system and hence it is termed as unit testing.
What are its benefits?
In simple words
“Calculator does fast and efficient calculation than manual human calculation.”
If you ask someone to get the answer for 9*8, he/she won’t take more than 2 sec for that. But if you ask the same person to get the result for 999*888, not only you will see a huge difference in response time but also you will not be sure about the correctness of output.
If you consider using calculator for achieving the same, you will notice that for every input we feed output will be quick and it will be more reliable.
What we do when we develop something?
When developers do manually testing of the code they have written the biggest problem is they (testing logic/process) will not be reusable. We are in the IT world so job switch is very common among developers and there is a big possibility that person who developed something and person who is modifying it are different.
Let’s talk about a scenario. Let’s say company asks Developer 1 to develop a Maths library.
Step 1 - Developer1 creates following code.
public class CustomMaths
{
public int Number1 { get; set; }
public int Number2 { get; set; }
public CustomMaths(int num1,int num2)
{
Number1 = num1;
Number2 = num2;
}
public int Add()
{
return Number1 + Number2;
}
public int Sub()
{
return Number1 - Number2;
}
}
Step 2 – Test the logic
Developer1 will test both Add and Sub function and confirms that everything is working fine.
Is it end - ?
No, Sometime later Developer 1 leave the organization and Developer 2 join as a replacement. Company demands him to add a new functionality to the Maths Library. They wants to add Div functionality and ask Developer 2 to make sure that DivideByZeroException is handled. (In short they also want to add zero validation to Numbe2)
Resulting Code ->
public CustomMaths(int num1,int num2)
{
Number1 = num1;
if (num2 == 0) { Number2 = 1; }
else { Number2 = num2; }
}
.
.
.
public int Div()
{
return Number1/Number2;
}
Now Developer2 will just test Div function and he will be in an impression that Add and Sub function are intact and work properly.
If you notice properly then you can understand
- Add and Sub function are internally using Number1 and Number2 variable.
- Number1 and Number2 are getting used in constructor.
- Constructor is modified in order to make Div function behave correctly.
- It means there is a possibility that Add and Sub functionality will also behave in unexpected manner.
- Finally it means Developer2 also need to test Add and Sub function (which he/she is not doing right now.)
Will proper documentation work out here?
Let’s say Developer1 will create some kind of document after the first release which explains how things need to be tested.
In real life it’s not possible. Developer1 will test Add and Sub functions using his thoughts. Let’s say he documented each and every step, which need to be followed while testing. But how should we make sure that Developer 2 follow all the steps properly. There is high possibility that Developer2 is not as smart as Developer1.
The Best solution will be Developer 1 will write some code,
- Which will test Add and Sub Function
- Which developer 2 will execute and confirms test is passed and so confirms function is working properly.
And that’s were Unit Test comes to picture.
Developer 1 will create a fast and reliable test methods which will be reused in every coming releases.
Note:There is a common misconception among developers. They think it takes more time to write code with unit test cases, and we don’t have time for that – In reality, unit testing would save your development time in the long run.
A simple example of unit testing using Visual studio
You will get tons of article on same, but I think better if we have a small demonstration here so that all food items will be in one plate.
Developer 1 Task
Step 1 - Create CustomMaths class library (just like above) with two functions Add and Sub
Step 2 - Create Unit Testing Project as Follows
Step 3- Add reference of previous class library to this newly created project
Step 4 - Create Test class has follows
[TestClass]
public class TestMathsClass
{
[TestMethod]
publicvoidTestAdd()
{
CustomMaths maths = new CustomMaths(6, 5);
int result = maths.Add();
Assert.AreEqual<int>(11, result);
}
[TestMethod]
public void TestSub()
{
CustomMaths maths = new CustomMaths(6, 5);
int result = maths.Sub();
Assert.AreEqual<int>(1, result);
}
}
Explanation – As you can see Unit Testing follows simple three steps.
- Arrange - Create objects and prepare everything needed to test functionality
- Act – Execute and get the output
- Assert – Compare final output with expected Output
Step 5– Build your solution and open test explorer window from Test > Windows > Test Explorer
Step 6– Right click Test cases and say Run Selected Tests.
Note: In the example we are using hard coded values (5 and 6) for testing but in real life scenario we will not use hard coded values rather will use some kind of data source like excel or database for input parameters and return value.
What makes Unit Test a good Unit Test?
I think now you are good with following things
- What is Unit Testing?
- Why we should we do it?
- How to do it?
So I think after this WWH (What, Why and How) it’s to time to learn how to write a good Unit Test.
In Database world any sql developer can go and create database but the person who know normalization well can develop and design database which will not contain any redundant data.
In the same manner any developer can go and write Unit Test but we cannot call every Unit Test a good unit test. Following are the key points which every Unit Test must have.
- Performance – Unit test must be very fast. It should not take much time to execute.
- Easy Setup–Writing lots of code for testing your logic is not a good practice. You should not end up with something where one logic will test another logic. Remember you are trying to test something which is complicated and make sure that your test method is very simple. a. Arrange everything which is required to test our logic.
b. Act on it by invoking our logic.
c. Assert and confirm whether output is matching to the expected output or not. - Result oriented–Test should always pass or fail. There must be a result. There should not be any intermediate halt.
- Order Independent– Every Test method should be independent of every other test method. Test methods should not share states among them. So the order in which test methods need to be execute should not be fixed. One can go and execute any method anytime and it will either fail or pass.
- Reusable – Test methods should be reusable. I feel it’s the most important feature every test method should have. We should create Unit Tests which will be more beneficial in future. Changes are integral part of any application development. But with every change we should not re cerate the Unit Test rather we should reuse.
- Single Logic Test – Every test method should test only one Unit of Work. If it is testing more than behavior it’s not proper.
- Less dependencies– Test method should be completely isolated from External dependencies (like Mail Server, other classes) and Environmental dependencies (like current date time).
- Meaningful – We should not write test methods for each and every logic in our application. Our Test method should be valuable and meaningful. It should be worth. For example in real life scenarios we should not write test method which will test addition logic. J. In simple words write test methods for only those logic which you really want to test and which you feel worth to be tested.
Untestable code?
Code which violates above principles can be considered as Untestable code.
There is a very good saying by great leader of our IT world “If you system is easy to Unit Test it will be easy to maintain code.”
Except “Less dependencies” point all can be managed and handled by developer easily. Proper understanding of SOLID principles lets design a system which will adhere to all of these 7 principles.
You can read about SOLID principle in detail
here.
We are in the world of object oriented programming and so we will talk in terms of real time objects. Objects interact with each other by calling methods and this is what we call as dependency.
Sometimes we also have dependencies to some environmental factors like system date time, File access rights etc. which can also make our code untestable.
How dependencies really affect Unit Testing?
Let’s discuss the scenario shown in above diagram. We have CustomerMiddleLayer class with a SaveCustomer function. Purpose of this function is to add a new customer entry to database and on successful insert send an email to Administrator.
Before we go and create Test Method for SaveCustomer Method let’s try to think what happen when our email server is not configured properly or when we don’t have email server on test environment?
The answer is Test method will always fail regardless of what result our database access layer generates. This makes our “Save customer”logic completelyuntestable. We will be sure about the fact that email server will be configured well in later stage and so for now we just want to make sure that other things in the “Save customer” function is working properly but we are not able to do it.
Visual studio 2012 Fakes for rescue
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
{
return true;
}
catch (Exception e)
{
return false;
}
}
}
Email library
public interface IEmailLibrary
{
bool SendEmail();
}
public class EmailLibrary : IEmailLibrary
{
public bool SendEmail()
{
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
- Create your own temporary class , inherit it from IEmailLibrary and use
- Use Mock frameworks like MOQ, Rhino MOCK etc. To read more about them click
here.
But I neither believe in
- Reinventing the wheel
- Nor asking neighbor for food when my wife can cook better.
I mean if we can achieve same behavior with the help of Visual studio 2012
fakes why to go somewhere else J
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()
{
CustomerMiddleLayer middleLayer = new CustomerMiddleLayer();
string CustomerName = "Sukesh Marla";
IEmailLibrary e = new StubIEmailLibrary
{
SendEmail=()=>true
};
string returnCustomerName = middleLayer.AddCustomer(CustomerName, e);
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
Stubs are really easy to use and understand but in real life projects we will not find DIC (Dependency inversion principle)followed everywhere. In real life we cannot go and create interface every time we end up with dependency. Many time we will stick to concrete classes instead of interfaces and abstract classes. Let’s rewrite the above code but this time without interfaces.
Customer Data Access Layer
(Same as above)
Email library
public class EmailLibrary
{
public bool SendEmail()
{
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()
{
CustomerMiddleLayer middleLayer = new CustomerMiddleLayer();
string CustomerName = "Sukesh Marla";
string returnCustomerName = null;
using (ShimsContext.Create())
{
ShimEmailLibrary.AllInstances.SendEmail = (@this) =>{ return true; };
returnCustomerName=middleLayer.AddCustomer(CustomerName);
}
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()
{
YearUtilities yearUtilities = new YearUtilities();
bool CurrenrResult = yearUtilities.IsTodayLastDateOfYear();
Assert.AreEqual<bool>(true, CurrenrResult);
}
[TestMethod]
public void TestForNotLastDay()
{
YearUtilities yearUtilities = new YearUtilities();
bool CurrenrResult = yearUtilities.IsTodayLastDateOfYear();
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()
{
YearUtilities yearUtilities = new YearUtilities();
bool CurrenrResult = false;
using (ShimsContext.Create())
{
ShimDateTime.NowGet = () =>new DateTime(2012, 12,31);
CurrenrResult =yearUtilities.IsTodayLastDateOfYear();
}
Assert.AreEqual<bool>(true, CurrenrResult);
}
[TestMethod]
public void TestForNotLastDay()
{
YearUtilities yearUtilities = new YearUtilities();
bool CurrenrResult = false;
using (ShimsContext.Create())
{
ShimDateTime.NowGet = () =>new DateTime(2012, 12,15);
CurrenrResult = yearUtilities.IsTodayLastDateOfYear();
}
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.
Conclusion
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.
I tried my best to put things in front of you. But if still any of you have any query, feedback, comment or suggest please feel free to forward to SukeshMarla@Gmail.com. I really appreciate each and every input of yours.
Keep coding, Keep learning and Keep sharing.
Don’t forget to vote and comment.
For technical trainings on various topics like WCF, MVC, Business Intelligence, Design Patterns, WPF and Basic fundamentals feel free to contact SukeshMarla@Gmail.com or visit http://www.sukesh-marla.com/
For more stuff like this click here. Subscribe to article updates or follow at twitter @SukeshMarla
See 600+ above FAQ questions and answers in .NET, C#, ASP.NET, SQL, WCF, WPF, WWF, SharePoint, Design Patterns, UML etc.