Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / load-testing

How to write Unit Test cases using VSTS

3.50/5 (5 votes)
11 Feb 2009CPOL4 min read 88.3K   661  
Visual Studio Team System (VSTS) comes along with inbuilt testing tools, which provide more effective and efficient ways to write test scripts for both Windows and web applications.

Overview of VSTS

Visual Studio Team System (VSTS) comes along with inbuilt testing tools, which provide more effective and efficient ways to write test scripts for both Windows and web applications.

VSTS is for management of large projects. In order to use the system, we have to set up a server and install it and maintain access to all users, and if they are in remote locations, we need to open the firewall to access it.

VSTS also allows a developer to aggregate multiple tests which have already been written, so that they can be executed by automated test agents to simulate up to a thousand users for load testing. Several agents can be run concurrently to increase the load in multiples of about a thousand. This whole process allows a team to reuse the work that was initiated for the various kinds of tests.

This also makes it easier for the developers themselves to execute a load test based on the Unit Tests of the individual code modules, so that they can identify problems at an earlier stage, saving time, and learning how to write better code.

Using ASP.NET Unit Tests, we can test classes and methods that are part of an ASP.NET website. This is often very similar to testing anything else, since we can use code generation on classes that are within the App_Code directory for the site. Unfortunately, it's not possible to generate tests for the page class itself (the one defined in the .aspx and .aspx.cs files for the page), due to differences in how Visual Studio handles these files:

CreateUTC.JPG

VSTS supports five key types of tests:

  • Unit Testing, in which we call a class and verify that it is behaving as expected.
  • Manual testing.
  • Generic testing that uses an existing test application that run as part of the biggest test.
  • Web testing to ensure the HTML apps function correctly.
  • Load testing to ensure the app is scalable.

Sample

C#
using Microsoft.VisualStudio.QualityTools.UnitTesting.Framework;
using System;
namespace Test
{
   /// <summary>
   ///This is a test class for VSTTDemo.LogonInfo and is intended
   ///to contain all VSTTDemo.LogonInfo Unit Tests
   ///</summary>
   [TestClass()]
   public class LogonInfoTest
   {
      private TestContext testContextInstance;
      /// <summary>
      ///Gets or sets the test context which provides
      ///information about and functionality for the 
      ///current test run.
      ///</summary>
      public TestContext TestContext
      {
         get
         {
            return testContextInstance;
         }
         set
         {
            testContextInstance = value;
         }
      }

      /// <summary>
      ///Initialize() is called once during test execution before
      ///test methods in this test class are executed.
      ///</summary>
      [TestInitialize()]
      public void Initialize()
      {
         //  TODO: Add test initialization code
      }

      /// <summary>
      ///Cleanup() is called once during test execution after
      ///test methods in this class have executed unless
      ///this test class' Initialize() method throws an exception.
      ///</summary>
      [TestCleanup()]
      public void Cleanup()
      {
         
         //  TODO: Add test cleanup code
      }


      // ...

      [TestMethod]
      // ...
      public void ChangePasswordTest()
      {   
      // ...
      }

   }
}

The test setup and cleanup methods are decorated with TestInitializeAttribute and TestCleanupAttribute, respectively. Within each of these methods, we can place any additional code that needs to be run before or after every test. This means that before each execution of ChangePasswordTest() corresponding to each record within the LogonInfoTest table, both Initialize() and Cleanup() will be executed. The same is true each time NullUserIdInConstructor and EmptyUserIdInConstructor execute.

Such methods can be used to insert default data in a database and then clean up the data at the end of the test. It would be possible, for example, to begin a transaction within Initialize() and then rollback the same transaction during cleanup such that, assuming the test methods use the same connection, the data state would be restored at the end of each test execution. Similarly, test files could be manipulated.

During debugging, it is possible that the TestCleanupAttribute decorated method will not run simply because the debugger was stopped before the cleanup code executed. For this reason, it is often a good practice to check for cleanup during test setup and execute the cleanup prior to the setup as necessary. Other test attributes available for initialization and cleanup are AssemblyInitializeAttribute/AssemblyCleanupAttribute and ClassInitializeAttribute/ClassCleanupAttribute. The assembly related attributes run once for an entire assembly, while the class related attributes run once each for the loading of a particular test class.

Approach

In order to use VSTS for unit testing a sample application and to resolve the HttpContext and Session related issues, we should follow the steps mentioned below. The below sample pseudo code on the sample application emphasizes the steps involved:

Pseudo code for Sample.aspx.cs

C#
using System.Diagnostics;
using System.Web.Hosting;
using System.Web;
using System.IO;
using System.Security.Permissions;
using System.Web.SessionState;

HttpContext Object Initialization

private TestContext testContextInstance;
 
public TestContext TestContext
{
    get { return testContextInstance; }
    set { testContextInstance = value; }
}

The Page object is available through the RequestedPage property of the TestContext object for the class. Since the actual type of the page is dynamically generated when the page is loaded, we can only provide this as an object of type Page, but it’s still possible to access members of the specific subclass of the page.

Session initializing and calls:

C#
[AspNetHostingPermissionAttribute(SecurityAction.InheritanceDemand, 
 Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermissionAttribute(SecurityAction.LinkDemand, 
 Level = AspNetHostingPermissionLevel.Minimal)]
public interface IRequiresSessionState { }

[TestInitialize]
public void TestInit()
{
    HttpContext.Current = new HttpContext(new HttpRequest("", 
                          "http://localhost", ""), 
                          new HttpResponse(new System.IO.StringWriter()));
    System.Web.SessionState.SessionStateUtility.AddHttpSessionStateToContext(
               HttpContext.Current, new HttpSessionStateContainer("",
               new SessionStateItemCollection(),  new HttpStaticObjectsCollection(), 
               20000, true, HttpCookieMode.UseCookies, SessionStateMode.Off, false));

    //Initialize your specific application custom Context Class.
    //Initialize User object initialized
}

[TestMethod()]
[DeploymentItem("Application.Web.dll")]
public void LoadTest()
{
    Test target = new Test ();
    TestProject1.ObjectName  accessor = new TestProject1.ObjectName (target);
        // write the test cases for the method.
}

Sample test case project

C#
/// <summary>
///This is a test class for _DefaultTest and is intended
///to contain all _DefaultTest Unit Tests
///</summary>
[TestClass()]
public class _DefaultTest
{

    private TestContext testContextInstance;

    [TestInitialize]
    public void TestInit()
    {
        HttpContext.Current = new HttpContext(new HttpRequest("", 
                              "http://localhost", ""), 
                              new HttpResponse(new System.IO.StringWriter()));
        System.Web.SessionState.SessionStateUtility.AddHttpSessionStateToContext(
                   HttpContext.Current, new HttpSessionStateContainer("",
                   new SessionStateItemCollection(), new HttpStaticObjectsCollection(), 
                   20000, true, HttpCookieMode.UseCookies, SessionStateMode.Off, false));

        //Initialize your specific application custom Context Class.
        //Initialize User object initialized
    }

    /// <summary>
    ///Gets or sets the test context which provides
    ///information about and functionality for the current test run.
    ///</summary>
    public TestContext TestContext
    {
        get
        {
            return testContextInstance;
        }
        set
        {
            testContextInstance = value;
        }
    }

    /// <summary>
    ///A test for Page_Load
    ///</summary>
    [TestMethod()]
    [UrlToTest("http://localhost")]
    [DeploymentItem("SampleProject.dll")]
    public void Page_LoadTest()
    {
        // TODO: Initialize to an appropriate value
        _Default_Accessor target = new _Default_Accessor();
        // TODO: Initialize to an appropriate value
        object sender = null;
        // TODO: Initialize to an appropriate value
        EventArgs e = null;
        target.Page_Load(sender, e);
    }

    /// <summary>
    ///A test for SetSession
    ///</summary>
    [TestMethod()]
    [DeploymentItem("SampleProject.dll")]
    public void SetSessionTest()
    {
        // TODO: Initialize to an appropriate value
        _Default_Accessor target = new _Default_Accessor();
        target.SetSession();
    }
}

Regarding Web.config

Web.config will not be supported while Unit Testing with VSTS. So, we should copy all the contents of Web.config except system.web and paste into App.config. App.config should then be placed in the test project folder.

Debug the test case

Use System.Diagnostics.Debugger.Break(); to debug the application.

C#
Void TestMethod()
{
    System.Diagnostics.Debugger.Break();
    //Some Statement
}

In VS2008, just right click and generate the test case. It automatically generates the test case for all the methods/selected methods, and also handles session issues with attributes.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)