Sunday, December 30, 2007

When you write unit tests for your ASP.Net applications you may at some point need to debug these tests. Although the Visual Studio’s Test menu has an option to debug your tests, I found this doesn’t work when running ASP.Net tests.

 
A simple way around this is to use the Debugger class located in the  System.Diagnostics namespace. The code snippet below shows how you would place a call to the Debugger.Break() method before the line of code you wish to start debugging at.

 [TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost/AspNetTDD1/Default.aspx")]
[AspNetDevelopmentServerHost(@"C:\code\AspNetTDD1\AspNetTDD1", "/AspNetTDD1")]
public void TestMethod1()
{

System.Diagnostics.Debugger.Break();
Page page = _testContextInstance.RequestedPage;

Button button = page.FindControl("Button1") as Button;
Label label = page.FindControl("Label1") as Label;

PrivateObject po = new PrivateObject(page);
po.Invoke("Button1_Click", button, EventArgs.Empty);

Assert.AreEqual("Did you hear that? They shut down the main reactor.
We'll be destroyed for sure", label.Text);
}

Now if you run your tests you will see the following dialog box.

 

You should click the Debug button which will display the Visual Studio Just-In-Time-Debugger dialog, here you should click the Yes button. This will open an new instance of Visual Studio with the code relating to the test loaded. You can now debug the test code using the standard options of Step Into (F11), Step Over (F10) etc.


posted on Sunday, December 30, 2007 10:17:01 AM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [1]
 Saturday, December 29, 2007
Introduction

With Visual Studio 2008 it is now possible to unit test you ASP.Net applications. This is achieved using three new method attributes HostType, UrlToTest and AspNetDevelopmentServerHost, along with the TestContext  and PrivateObject classes. Using the combination of these attributes and classes it is possible to run tests for an ASP.Net page in the development server included with Visual Studio or IIS.

 
Example 1:
This is a very simple web page, it consists of a button that when clicked will display some text in a label.

1.      Create a new Web application project in Visual Studio 2008.

2.      Add a test project to the solution with a test class called DefaultUnitTests.cs.  Your solution should now contain the following.


3.      We’ll start by defining the test. So open DefaultTests.cs. The first thing we need to do is add a using directive for Microsoft.VisualStudio.TestTools.UnitTesting.Web this namespace contains all the attributes relating to testing web pages. You will also need to add using directives for System.Web.UI and System.Web.UI.WebControls you need these as you will be using web controls in the test method.

4.      We are now able to add the test method. As this test will be executed against a web page there are a number of attributes that must be added to the method so that the tests are executed in the correct environment. The first of these is the HostType attribute which allows you to specify the type of host that the test will run in. As we want to run our tests in the ASP.Net engine we will specify the string ASP.Net.

5.      The next attribute that needs to be specified is UrlToTest. When using the ASP.Net development server the port that the ASP.Net development server runs on is randomly assigned, therefore when testing with the ASP.Net development server the URL will be fixed up to use the correct port number. However if you run your tests in IIS then no fix up is needed.

6.      The final attribute that needs to be applied is AspNetDevelopmentServerHost. This is used to tell the ASP.Net development server where the web site is located on disc, if you plan to test only with IIS then you can omit this attribute.

7.     Now that all the attributes have been applied to the method we can define the method body. This is where we will use the TestContext and PrivateObject classes to get a handle to the page and invoke methods.

8.      The TestContext contains the RequestedPage property that allows access to the Page object that was created to server the URL requested by the test. Once you have a handle on the Page object you can use the pages FindControl method to access the various controls on the page.

9.      Next create an Instance of a PrivateObject passing the page as a parameter to the PrivateObjects constructor. Once the PrivateObject has been created we can use the Invoke method to call any method of the page object. In this case we will be calling the event handler of the buttons click event, thus simulating the process of the user clicking the button. For more information on PrivateObjects see my earlier post. The code snippet below shows the full test method.

   [TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost/AspNetTDD1/Default.aspx")]
[AspNetDevelopmentServerHost(@"C:\code\AspNetTDD1\AspNetTDD1", "/AspNetTDD1")]
public void TestMethod1()
{
Page page = _testContextInstance.RequestedPage;

Button button = page.FindControl("Button1") as Button;
Label label = page.FindControl("Label1") as Label;

PrivateObject po = new PrivateObject(page);

po.Invoke("Button1_Click", button, EventArgs.Empty);

Assert.AreEqual("Did you hear that? They shut down the main reactor.
We'll be destroyed for sure", label.Text);
}

10.  Running the tests at this stage will cause the tests to fail with a null pointer exceptions as the controls and event handler have yet to be defined.

11.  We will now add the controls to the page and define the event handler. Your aspx page should contain a definition for a label and button control similar to this.

   <asp:Label ID="Label1" runat="server" />
<br />
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />

12.  Double click on the button to add an on click event handler.

13.   If you run the tests run (keyboard shortcut: Ctrl + r + a) or click Tests -> Run -> All tests in solution.

14. The test will fail as the label contains an empty string. Therefore we need to add the following to the button click event handler


protected void Button1_Click(object sender, EventArgs e)
{
     // can use guess the film?
     Label1.Text = "Did you hear that? They shut down the main reactor.
                   We'll be destroyed for sure";
}

15. Build and run the test again and it should now pass for you.

This is a very simplistic example of unit testing an Asp.Net page, but this has been done on purpose so that you can see the nuts and bolts of the technology, this should give you an idea of the attributes needing applied to a method that tests ASP.Net pages, you should also now understand how to obtain a handle to the Page object and access the controls and event handlers contained within the page.



Example 2:
In this example I will use the same principles as described in example 1 but I  will now use the UrlToTest attribute to execute a different URL for the two test methods. The page will look for a parameter from the query string and display this in label. 

As the process of creating the solution is identical to that of example 1 I will outline only the additions to this solution. You can download complete solution file for both example 1 and 2 at the end of this post.

  •  We now have two test methods one of which will pass and the other will fail, this is to illustrate that it is possible to invoke each test against a different URL in this case one with the parameter included in the URL and the other without the parameter. The code snippet below shows one of the test methods with the UrlToTest attribute applied.

    [TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost/AspNetTDD2/Default.aspx?demoParam=Hello")]
[AspNetDevelopmentServerHost(@"C:\code\AspNetTDD2\AspNetTDD2", "/AspNetTDD2")]
public void TestMethod1()
{
     Page page = _testContextInstance.RequestedPage;

     // need to manually invoke the Page_Load method.
     PrivateObject po = new PrivateObject(page);
     po.Invoke("Page_Load", page, EventArgs.Empty);

     Label label = page.FindControl("Label1") as Label;

     Assert.AreEqual("Hello", label.Text);
}

  • I have also had to use a PrivateObject to invoke the Page_Load method. When unit testing a page the methods normally called as part of the pages life cycle are not invoked therefore you must use a PrivateObject to manually invoke the methods if their execution is required.


Example 3:
In this example I will show a slightly more realistic implementation of an ASP.Net page. The page uses a data access component to retrieve a string and display the value in a label on the page. In this example I will again touch on the use of a PrivareObject and mock objects. You can download the complete solution for this example at the end of this post.

Again as the process of creating the solution is identical to that of Examples 1 and 2 I will therefore skip the step by step explanation and explain only the more interesting parts of the code, you can download the complete solution at the bottom of this post.

  • The basic class diagram below shows the basic structure of the storage components used in this example.
  •  Implementing the RealDataAccess component is unnecessary for this example therefore I will not provide an implementation for this. In a real application the RealDataAccess class could involve connecting to a database which would obviously add an extra layer of complexion that would  be a distraction from the purpose of this example.
  • As always the first thing we’ll define is the test method. The code snippet below shows this test. As this method will be testing and ASP.Net web page I need to add the attributes TestMethod (mark this as a test method), HostType (indicate that this test should run in the ASP.NET), UrlToTest and AspNetDevelopmentServerHost (needed as I’m running my tests in the ASP.Net development server, if you want to use IIS you can omit this attribute).

    [TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost/AspNetTDD3/Default.aspx")]
[AspNetDevelopmentServerHost(@"C:\code\AspNetTDD3\AspNetTDD3", "/AspNetTDD3")]
public void TestMethod1()
{
Page page = _testContextInstance.RequestedPage;

Button button = page.FindControl("Button1") as Button;
Label label = page.FindControl("Label1") as Label;

PrivateObject po = new PrivateObject(page,
new PrivateType(page.GetType().BaseType));

po.SetField("_dataAccess", new MockDataAccess());
po.Invoke("Button1_Click", button, EventArgs.Empty);
       Assert.AreEqual("Welcome young Skywalker," +
"the force is with you but you are not a Jedi."
,
label.Text);
}

  •  The actual test method should be straight forward as it reuses techniques from previous examples. First the TestContext is used to get a handle on the page object, from this a handle can be gotten to the label and button controls that have been placed on the page.
  • We then make use of a PrivateObject to set the page to use the MockDataAccess object. The code snippet below shows how the PrivateObject is created for the page. A PrivateType has to be passed to the constructor of the PrivateObject. Here I pass page.GetType().BaseType to the PrivateType constructor. This is necessary as the type of the page is generated dynamically and in this scenario I want to manipulate a private field declared in the code behind of the page therefore I need to ensure the PrivateObject is constructed with the type of the code behind otherwise I would not be able to manipulate the private field.

PrivateObject po =
new
PrivateObject(page, new PrivateType(page.GetType().BaseType));

  • At this point everything has been setup and configured to run in a controlled environment, as the page uses the mock data access component we know exactly what to expect.
  • To carryout the actual test we need to click the button, to do this in a unit testing scenario we don’t want to have to manual click a button each time as one advantage of unit tests is they can run unattended as part of a night build process. In order to simulate a user clicking the button we can simply use a PrivateObject to invoke the click handler of the button.
  • Once the button has been clicked it is simply a matter to checking that the label’s text has been updated with the correct text.

 
Conclusion
Hopefully from these simple examples you will have gained an appreciation of the features now available with Visual Studio 2008 that allow you to conduct unit testing on your ASP.Net applications.


Example Solutions

AspNetTDD1.zip (39.09 KB)

AspNetTDD2.zip (32.71 KB)

AspNetTDD3.zip (64.01 KB)
posted on Saturday, December 29, 2007 12:48:43 AM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [4]
 Saturday, November 17, 2007

The practice of coding against interfaces is already a well recognised best practice for software development, one of the advantages of this is that it helps loosen the dependencies between a class and the various other classes it uses. An application where this can be extremely useful is when unit testing your code, by loosening the dependencies of a class it becomes possible to test a class in isolation.

A good example of how to use these would be in data access classes, the real data access class would undoubtedly make calls to a physical database which would required configuration etc. However when testing a class that depends on the data access class we don’t want this dependency. Therefore the solution is simple. Define an interface, make both he real and mock classes implement this interface, the only difference is that the real implementation would go ahead and make calls to insert, update and delete from a database the mock will return only hard coded values so that you know exactly what to expect when testing a class that uses the data access components.

There are various frameworks that help to facilitate the creation of mock objects such as NMock, these are slightly more complex and give some extra features but the principle of coding to interfaces must be adhered to in order to take advantage of such frameworks.

To see an example of using mock objects see my post on PrivateObject, here I have simply used standard interfaces as this proved effective enough to conduct the testing. If your situation requires something more you can always look into NMock which is a free download.

posted on Saturday, November 17, 2007 2:53:25 PM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [1]
 Thursday, November 15, 2007

PrivateObject have been included in Visual Studio 2005 team edition but since the release of Visual Studio 2008 they have been included in the professional edition, making them available for a wider number of developers.

So what’s the fuss all about? Simply as I’ve stated in earlier posts a PrivateObject allows you to access private members of an object. This can be extremely useful when unit testing an application as combined with mock objects these can create the mechanism that allows tests to be conducted in isolation.

For example, take a look at the class diagram below. In this scenario the person class provides the method CalculatePay this will return the amount of pay an employee should receive. To do this the Person class will make a call to the GetHours() method of a persons TimeSheet. The time sheet is declared as a private variable and is therefore inaccessible to anything outside of the Person class.


So how do we test the CalculatePay method? The TimeSheet class will possibly make calls to a database or an enterprise system that holds this data therefore introducing many possible points of failure, so simply testing all at once won’t give us the full benefit of unit testing, it might tell us something has gone wrong but it can’t tell us what or where, and we all love error message that tell us something has gone wrong contact your administrator, personally I hate this type of error, if something has gone wrong I’d like to know what it is exactly as this can save significant time when fixing the problem. The way we get the specific details of what has gone wrong is isolating the tests, only by isolating the tests and completely controlling the situation can we accurately predict what a method should do, and the way I go about this is using Mock objects and the PrivateObject class.

For more details on Mock Objects see my post on the topic.


In this solution I will make the TimeSheet class implement an interface that defines the GetHours method. I will then create a new class called MockTimeSheet that implements the same interface. However the MockTimeSheet class will return a hard coded value for the hours work, this is important as a hard coded value allows me to know exactly what to expect when I call the method. After defining the mock object I will use the PrivateObject to update the private fields of the Person class before running the test.


The class diagram below gives an overview of  what the solution will now look like.




We’ll start to implement this example and as always we’ll start by implementing the unit tests first.

  1. Open Visual Studio 2008 and create a new blank solution called “PrivateObjectExample”.
  2. Add a new test project called PayrollTests
  3. Add a new class library project with a single empty public class called Person. The solution should now have the following items.




  4. Rick click on the PayrollTests project and select Add -> Unit Test






  5. Tick the tick box beside the Payroll project icon and click ok.






  6. We now want to call the CalculatePay method in a controlled manner so that we know exactly what to expect and therefore what to test against. To do this we will need to set the hourly rate and control the number of hours that the TimeSheet class returns. This is where mock objects come into play. Add a new interface to the Payroll project called ITimeSheet which has one method GetHours. The code snippet below shows what the interface should look like.

    namespace Payroll
    {
    interface ITimeSheet
    {
    double GetHours();
    }
    }

  7. We will now create a mock object that implements the ITimeSheet interface. Because the mock object is specific to testing it is therefore added to the PayrollTests projects. Right click on the PayrollTests project and select add new class. Call the class MockTimeSheet and implement the ITimeSheet interface the code below shows what you should have.

    using Payroll;

    namespace PayrolTests
    {
    public class MockTimeSheet: ITimeSheet
    {
    public double GetHours()
    {
    return 38;
    }

    }
    }

  8. We can now start to define the test. To start with we create an instance of the Person class and set the HourlyRate property to £5 per hour. At this point we now need to set the class to use the mock time sheet. This is done by creating an instance of the PrivateObject class and calling the SetField method. The set field method takes two parameters, a string which is the name of the variable you wish to set and the second parameter is the value you wish to assign to the private field. After the private field has been set it is simply a matter of calling the CalculatePay method of Person class and using the Assert class to test that the calculated pay matches what is expected. The code snippet below shows the code for the test method. Just for interest note the call to the Assert.AreEqual takes three parameters, this third parameter is a message that is displayed when the test fails.

    [TestMethod()]
    public void CalculatePayTest()
    {
    Person person = new Person();
    person.HourlyRate = 10.00;

    PrivateObject po = new PrivateObject(person);
    po.SetField("_timeSheet", new MockTimeSheet());

    double pay = person.CalculatePay();

    Assert.AreEqual(38, pay, "Calculated pay does not match the expected pay!");
    }

  9. You can download the complete solution here.
    PrivateObjectExample.zip (60.25 KB)
posted on Thursday, November 15, 2007 11:13:34 PM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [0]
 Wednesday, November 14, 2007

Introduction
In my last post I gave a very brief introduction to the Test-Driven Development (TDD) process and demonstrated a very simple project in Visual Studio 2008 that showed how to create tests for a class. In this post I will introduce more of the tools and classes available in Visual Studio 2008.

In this post I will look at:

  • The TestContext class.
  • The Attributes available for defining test classes and methods.
  • The Assert class.
  • Private objects
  • Debugging tests within Visual Studio 2008.

The TestContext class
The TestContext class allows you to get a handle on the context in which the test is being executed. From this you can obtain useful information. For example when testing an ASP.NET application the TestContext class allows you to get a handle to the Page class. From this you will then be able to get a handle to the various controls contained on the page, this is an example I will expand upon in future posts.

 When you use the wizards built into Visual Studio 2008 to generate your unit test classes a TestContext property and corresponding member variable will be automatically added to your class. The runtime will take care of setting this property for you, therefore freeing you to simply use the TestContext as you need. The code snippet below shows the definition of the TestContext property and the corresponding member variable, this is not code you will have to write unless you are writing your test manually.

        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;
}
}

Attributes for Testing
All classes related to unit testing is Visual Studio 2008 are located in the namespace Microsoft.VisualStudio.TestTools.UnitTesting. I’ve already introduced two attributes in my last post the TestClass and the TestMethod attributes, these are the most common attributes that you will need for every test you write, the list below illustrates some of the other attributes that you may find useful when writing tests.

AssemblyInitialize and AssemblyCleanup
Allows you to identify methods that should be called before any tests in an assembly are executed and after all tests have completed.
 

ClassInitialize and ClassCleanup
Similar to the AssemblyInitialize and AssemblyCleanup except these are used to identify methods that are called before and after all tests in a test class are executed.

TestInitialize and TestCleanup
Again similar to AssemblyInitialize, AssemblyCleanup, ClassInitialize and ClassCleanup these attributes allow you to define methods that should be called before and after each individual test is executed.

Description
This attribute allows you to include a descriptive string that can then be listed in the test results window. The code snippet illustrates applying this attribute to the TestAddPositiveNumbers methods from my previous post and the screen shot shows how the description is displayed in the test results window. This can be a useful addition to helping convey the reasons for having a test but personally I would recommend striving to create meaningful names for your tests methods, avoid using names like ‘Test1’ for your test methods.

        [TestMethod]
[Description("Try and add two positive Numbers (2+2) and ensure that the answer is 4")]
public void TestAddPositiveNumbers()
{
Calculator cal = new Calculator();
int result = cal.Add(2, 2);
Assert.AreEqual(4, result);
}



Note: By default the description column is not displayed in the test results window, to display this column right click on the test results window and select “Add/Remove Columns…” this will display the following dialog that allows you to select the columns you wish to display.

 




ExpectedException
A very useful attribute this allows you to tell the runtime to expect a particular exception when running a test. When conducting unit tests you should be testing both normal and erroneous conditions, so you should pass invalid data to your methods and use unit tests to verify that your method can handle the error conditions appropriately. This is where the ExpectedException attribute can be useful. Normally if an exception occurs while executing a tests this will cause the test to fail, however telling the runtime to expect the exception will allow the test to pass, provided the exception raised match the type expected.


To illustrate this I have added a divide method to the calculator class from my last post. One of the tests and the implementation of the divide method are shown below.

HostType
This attribute identifies the test as being run outside of the current environment. For example specifying the string “ASP.NET” as the parameter to this attribute allows you to run tests in the ASP.NET development server. This is an attribute I will explore in more depth with later posts when I’ll be looking at testing an ASP.NET application.

For more information on the attributes available and their usage see the MSDN documentation.

The Asset Class
Central to helping you construct unit tests the Assert class provides a set of static methods that evaluate a Boolean condition. If the condition evaluates to true then the assert passes otherwise the assert fails and the unit test will be listed as a fail in the test results window. This is a list of some of the methods the Assert class provides, for more details on these check out the MSDN documentation. At this stage I’m only listing them to make you aware of their existence, in later posts I will use these as I need to illustrate points.

  • AreEqual
  • AreNotEqual
  • AreNotSame
  • AreSame
  • Fail
  • IsFalse
  • IsInstanceOfType
  • IsNotInstanceOfType
  • IsNotNull
  • IsNull
  • IsTrue

Private objects
In the past when I’ve been writing unit test I have been trying to test a class which relies on another class which has an instance of this class as a private field, and in keeping with the ethos of unit testing by testing each class in isolation this has presented me with a dilemma, do I test the two in conjunction, or do I expose some means of allowing the field to be set. Neither of these has ever proved to be an ideal solution, testing in conjunction is a big no and writing extra code to make a field publicly available doesn’t sit well, if there was no need for the outside world to know of this field before then it should be private. With private objects you now have the ability to solve both of these problems. My next post will give an example of using private objects.

 Debugging tests in Visual Studio 2008
Debugging unit tests with Visual Studio 2008 is straight forward simply follow these steps: 

1.  Open your solution that contains the test projects

2.   Open the class that contains the test you wish to debug and add a breakpoint to that test.

3.    Select Test -> Debug -> All Tests in Solution. The keyboard short cut to debug all tests is Ctrl+R Ctrl+D

 An alternative to debugging all tests in the solution is to use the test results window to select the tests you wish to debug. Then click on the drop down menu on the Debug button on the test results window toolbar and select “Debug Checked Tests”.


Conclusion
In my previous post I identified the TDD process and in this post I have built on this to introduce many of the features available in Visual Studio 2008 to facilitate unit testing. In subsequent posts I will get more practical with code examples that show how to use these features. The first of these will introduce the use of private objects with some example code.

posted on Wednesday, November 14, 2007 8:51:52 PM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [0]