If the term Unit Testing is totally new for you then here are a few definitions that will get you started about the concept€¦
What is a Unit in code?
A unit is typically a code block with a defined simplified functionality. Such a code block can be a function or a class.
What is Functionality?
Functionality is an operation that will either process input and return output or perform action that modifies the state of the object/system.
What is Unit Testing?
Each unit is tested programmatically in isolation to verify its independent behavior.
- Establishes an artificial environment.
- Invokes the operation.
- Checks the results returned against some known value, thus verifying that the unit performs the defined functionality as expected.
Or precisely, a code that executes and verifies a piece of code which is part of the main system.
Now that you know what Unit Testing is, quite possibly you have also developed those initial doubts, first and foremost€¦
Why do we need Unit Test?
For two simple reasons:-
- Unit tests check their own results and provide immediate feedback
(can also be configured to run automatically).
- Unit tests increase the stability of software.
Consequently enables you to develop more confidence in the code.
You will be more comfortable refactoring code and adding new features to the code that is unit tested. Whereas if the code is not unit tested then you will be paranoid about refactoring or adding new features because you don€˜t know what might break as a result of change.
For those who already know what Unit Testing is but still do not practice it, for sure they have there own valid reasons, lets just analyze some of the standard reasons:-
- Don’t have sufficient time to unit test.
-The time spent on unit testing is actually the time saved from debugging.
- The client wants us to develop code, not write unit test.
-The client surely does not want you to create bugs, unit test helps prevent bugs.
- I am supporting a legacy application without unit tests.
-With legacy application you can reform each unit by introducing unit test for each unit that is modified.
- QA and User Acceptance Testing are far more effective in finding bugs.
-True, but that does not give reason to developer for passing stupid mistakes to QA or User. Further defects can be found and fixed before they get formed. Hence less time spent on debugging.
- Effort of unit testing is more than the effort of writing code and testing it.
-There are many good frameworks that simplify your effort of writing unit tests. The point is being aware of such frameworks and there advantages.
- Unit testing is for novice programmers not for me.
- Unit test is intended to standardize the quality of code produced by a team with varying expertise of members. A good unit test demonstrates what all points where taken in consideration while writing the good code. If you think you never make mistake in your code then share your expertise with fellow programmers by writing good unit tests.
- I don’t know how to unit test or I don’t know how to write good unit tests.
- Read on to know about writing good unit tests.
If you need some more convincing then refer to Eric’s and & Brian’s – Top 12 Reasons to Write Unit Tests:
http://onjava.com/pub/a/onjava/2003/04/02/javaxpckbk.html
And Ian Nelson’s – 12 Reasons why he love Unit Tests:
http://ianfnelson.com/blog/why-unit-test/
The reason why I write Unit Test is because it demonstrates the ingenuity of every piece of code that shapes my perfect system. And with every successful unit test I feel the excitement of achievement.
How to write Unit Tests?
No matter which framework you chose fundamentally things remain same:-
You need one or more classes where you will write methods with code that will test other classes and functions of your main code. These classes are called TestClass in VSTS (and TestFixture in NUnit). Such classes are marked with TestClass attribute (or TestFixture in NUnit).
The methods of the Test Class that execute a unit of the main code and verify the result are called TestMethod (or Test in NUnit). These methods are marked with TestMethod attribute (or Test in NUnit).
At times there might be a need to perform certain initialization operations before running each of the Test methods such initialization operation can be written inside a TestInitialize method (or Setup in NUnit). Correspondingly the cleanup operations that should be performed after each Test can be written in TestCleanup method (or TearDown in NUnit).
VSTS Test example:-
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class SampleUnitTest
{
[TestInitialize()]
public void Init() { }
[TestMethod]
public void TestOperation() { }
[TestCleanup()]
public void Destroy() { }
}
NUnit Test example:-
using NUnit.Framework;
[TestFixture]
public class SampleUnitTest
{
[SetUp]
public void Init() { }
[Test]
public void TestOperation() { }
[TearDown]
public void Destroy() { }
}
Apart from these commonly used methods there can be additional methods provided based on the selected framework, like €€œ static ClassInitialize (or TestFixtureSetup in NUnit) and static ClassCleanup (or TestFixtureTearDown in NUnit). ClassInitialize executes only once before any test method in the test class is executed and ClassCleanup executes only once after all test methods in the test class has been executed.
Further, apart from the above attribute classes of the framework another very important class is the Assert class that contains static methods for comparison and verification of results of the test against some expected values.
Having the above fundamental knowledge of Unit Testing, we are now ready to write some example.
I do not prefer replicating the classic LoginInfoTest example by Mark Michaelis and extended by authors at codeproject.com and other technical blogs. Rather I have something very simple (and my favorite) a variation of €œHello World€, the €œHello User€ example.
Step 1: Create our main application
Lets create and assembly HelloUser with a class Greeting with a method Greet that will return greeting message string for the given user.
namespace HelloUser
{
/// <summary>
/// Greets User
/// </summary>
public class Greeting
{
/// <summary>
/// returns greetings based on given user
/// </summary>
/// <param>name of the user</param>
/// <returns>greeting for the user</returns>
public string Greet(string userName)
{
if (string.IsNullOrEmpty(userName))
return “Hello User”;
switch (userName)
{
case “Kamal”:
return “Hi Kamal”;
case “Shameer”:
return “Hey Shameer”;
case “Roy”:
return “Hoi Roy”;
default:
return “Hello ” + userName;
}
}
}
}
Note: In a Test Driven Development approach we would not have implemented the method before writing the following test, but for simplicities sake we will not get into TDD.
Note: Although I have marked the class and method as public for simplicities sake, the auto code generation of VSTS is also capable of generating test code stubs for non public members, however the generated code stub will be quite complex to understand.
Step 2: Creating Unit Tests
- Perform a mouse right click on the class Greeting, that will give you an option to Create Unit Tests.
- Selecting the option will open a dialog asking for a project to which the Unit Test Class should be added.
- The default and recommended option will be create a new test project. And that will ask you to name your new test project. Lets name it has TestHelloUser.
- The TestHelloUser project gets created with a class GreetingTest with a TestClass attribute and a lot of code and comment (compared to the size of our application code). For now lets just ignore (or remove) the rest and focus on the Test Methods.
- For our example two test methods stubs would have been auto created, namely GreetTest and GreetingConstructorTest. Since we are relying on the default constructor of our Greeting class (or in lay terms do not have a constructor for Greeting class). Let us just delete the GreetingConstructorTest method completely.
- Now the only Test Method we have and are concerned with is the GreetTest method that is supposed to perform Unit Test on our Greet method of Greeting class in the main assembly. As you would notice most of the code you need is already create, that is creating instance of Greeting class, invoking the Greet method and Asserting expected and actual value returned. All that we need to do in this method are:
- Specify the input value of userName, (say €œBart€)
- Specify expected value, (say €œHello Bart€)
- Remove the Assert Inconclusive operation (VSTS (or more precisely, MSTest) adds this default assert to warn about test stubs (test methods) that have not been modified manually)
- With the above changes our Test Method should look like:
[TestMethod()]
public void GreetTest()
{
Greeting target = new Greeting();
string userName = “Bart”;
string expected = “Hello Bart”;
string actual;
actual = target.Greet(userName);
Assert.AreEqual(expected, actual);
}
- The last step left is running our Unit Test, select menu option
Test >> Run >> Tests in Current Context
- That should run the test and produce a Test Results dialog, reporting whether the test passed or failed. Double clicking the result should open result detail also mentioning the time it took for the test to run.
That’s it?
Well, yes that completes our example and tutorial about Unit Testing with VSTS, unless you are inquisitive about some automatically added files to your solution under Solution Items folder.
I will not get into the details as this is already beyond the topic (and honestly I don’t know much) but just one feature as a bonus gift for readers who have reached so far and also because I find this feature very useful and that is Code Coverage.
In the Solution Items folder of our above solution you will find a file named LocalTestRun.testrunconfig file. Double click this file to open Test configuration Dialog.
Select the Code Coverage option to specify assemblies to be instrumented or (observed) for Code Coverage. Select the HelloUser assembly and Apply and Close.
Run the Test Again the Test Result dialog will show the result of Unit Test (GreetTest), double clicking which you can see the same Result Details.
Now, rather than performing a mouse double click on the Result for result detail perform a mouse right click on the result that will show you a set of options, select the option Code Coverage Results . That will open the Code Coverage Results window with a tree view for the HelloUser assembly. Expand the tree nodes to review the code coverage percentage and reach till the Greet method. Double click the Greet method and you will find the Greet method color coded, showing the lines executed during the test highlighted with a light blue color and the line not executed during the test highlighted with a light pinkish color (I am sorry I don’t know the exact name of the color). And this will help you analyze and decide the input values for your further Unit Tests that will perform more code coverage.
Apart from the ability to create Unit Tests and review Code Coverage, VSTS Unit Testing Framework provides features for pulling test data from external database and also provides an integral mock framework for creating mock objects for unit tests.
How to write good Code and good Unit Tests?
A basic rule that I follow is a code that cannot be easily unit tested is the code that should be refactored. So, simple Unit Tests also prove that your code is well structured.
Further the following best practices describe the principle for writing good Code and Unit Tests:
- Write code that is easy to Unit Test.
- Code a little, test a little, and code a little, test a little…
- Build in testability from the very beginning.
- Unit test each piece before integrating them.
- Each test should be independent of other tests and can be run autonomously.
- Run your tests as often as possible.
- Avoid creating unit test dependency on machine or system state. Like initial database value or directory path.
- Use Initialize and Cleanup to set and clear system state for Unit Tests.