Monday, May 23, 2016

Visual Studio: Developing Unit Tests

On a typical software project developers are responsible for writing per-method tests called unit tests. Such tests exercise the code within a method but typically do not exercise end-to-end functionality. For example, units tests would not invoke web services, access a database, etc.

It is unrealistic from a time/cost perspective for developers to write tests that cover every line of code within a project so a goals are set on a project. A common goal is that the tests written by developers achieve fifty percent coverage with respect to the lines of code within the project. Visual Studio provides the tools and infrastructure that the support the development of unit tests and measuring metrics such as code coverage.

To understand this consider the following solution, AnEntireApplication, which contains a single project (a Windows console application), TheCode:



This console application project, The Code, contains a source file, Worker.cs. In order to demonstrate Visual Studio's support for developing unit tests, such tests will be developed to exercise the methods of the Worker.cs source file which contains the Worker class.

The first thing to do when developing tests is to organize their location within the solution. The most straight forward way to do this is to create a folder in the solution called "Tests" and to place each test-related project associated with the solution in the Tests folder. To create this folder right click on the solution name within Solution Explorer and select Add | New Solution Folder:



When prompted create a solution folder named, "Tests":


To add a Unit Test project to the solution right click on the Tests folder and select Add | New Project:


Selecting New Project, displays the New Project dialog. Within this dialog select Installed | Visual C# | Test | Unit Test Project:


The project containing the code to test is TheCode project. The Unit Test Project to be created will be named TheCodeTest. The name is identical to the project to test with the name Test appended.

When the Unit Test project is added to the solution it appears as follows:



TheCodeTest unit test project will be testing the clases of TheCode console project. For this reason a reference should be added to from TheCodeTest to TheCode. This is achieved by right clicking on the References folder and from the contact menu select, Add Reference:



Selecting Add Reference from the Context Menu displays the Reference Manager dialog for the TheCodeTest project:


Prom the Projects tab select TheCode so TheCostTest unit test projects references project containing the code to be tested, TheCode:


As you can see above, the References for TheCodeTest project now contains a reference to TheCode.

The Unit Test project that was crated came pre-seeded with a sample unit test class, UnitTest1:


A clean way to approach testing is to have one test class per-class being tested. For this reason the UnitTest1 class and source file should be renamed WorkerTest as they will be testing the Worker class:


The attributes associated Unity Test project a predicated on common sense. Any class used to test is adorned with the [TesteClass] attribute and any method executing a test will be adorned with a [TestMethod] attribute.

The code associated with the TheCode class is as follows:

public class Worker
{
  public bool IsItSo(string data)
  {
    if ((data == "A") || (data == "B") || (data == "C"))
    {
      return true;
    }

    else
    {
      return false;
    }
  }

  public bool IsThatSo(string data)
  {
    switch (data)
    {
      case "A":
      case "B":
      case "C":
        return true;

      default:
        return false;
    }
  }
}

As the previous code snippet shows, the class to test exposes two methods IsItSo and IsThatSo. Once again the common sense design pattern should be applied when creating test methods. To understand how this consider the following from the WorkerTest class whose responsibility is to test the Worker class:


Notice above that there is a method defined, TestIsItSo, whose purposes is to test the Worker class' IsItSo method. Also notice above that there is a method defined, TestIsThatso whose purpose is to the the Work class's IsThatSo method.

The code associated with the IsItSo method is straightforward. If the parameter data is set to “A” or “B” or “C” then IsItSo returns true otherwise the method returns false. The TestIsItSoMethod should follow some obvious steps:
  1. Create an instance of the Worker class
  2. Invoke the IsItSo method passing in “A” as a value
  3. Verify the return value returned is set to true.
  4. Repeat steps 2 and 3 above by pass in “B” and “C” as a parameter.
  5. Pass in “D” as a parameter
  6. Verify the return value is set to false
At the top of the TestWorker class, a using statement was created where Visual Studio created the source file:
using Microsoft.VisualStudio.TestTools.UnitTesting;

The using Microsoft.VisualStudio.TestTools.UnitTesting; namespace contains a class called, Assert, that is used to test the return values for the methods to be tested. The Assert class exposes static methods such as:

  • IsTrue
  • IsFalse
  • AreEqual
  • AreNotEqual
  • IsNull
  • IsNotNull
Each of the previous methods (and there are a lot more of them within the Assert class) are designed to cause the test to fail if the assertion is false. The test passes if the assertion is true. Given that IsItSo returns a boolean, it makes sense to validate this methods return value using IsTrue and IsFalse. A example of a test case for IsItSo is as follows:

Worker worker = new Worker();
bool result;

result = worker.IsItSo("A");
Assert.IsTrue(result);

In the previous snippet, we expect the “result” parameter to be assigned a value of true when IsItSo is passed a string value of “A”. The Assert class’s IsTrue method tests the value of “results” and insures it is “is true” and hence the test passes passes. If IsItSo had returned false then the test case would have failed.

To be thorough the code for the TestIsItSo is as follows where functionality verifies each code path in the Worker class’ IsItSo method:




The TestIsThatSo method similarly tests the code associated with the Worker class’ IsThatSo method:


At this point, it is possible to run the tests which is done using Test Explorer. To display Test Explorer select the Test | Windows | Test Explorer:


From Text Explorer the tests can be run by clicking on the project and selecting Run Selected Tests:


Since the project was clicked on within Test Explorer all tests for the project are run which displays the following at the bottom of Test Explorer:

The test would pass if the covered one percent of the code or if the covered one hundred percent of the code. To see that actual code coverage invoke Analyze Code Coverage for Selected Tests:


The hierarchy of coverage can be expanded to reveal the following:


Test coverage applies to both the code being tested (TheCode project) and the test code itself (TheCodeTest project). Our target was to test the Worker class' IsItSo and IsThatSo method. The percent coverage for these methods is one hundred percent so it looks like we have done our job.


No comments :

Post a Comment