Thursday, February 28, 2008
Just a quick shout to anyone who hasn’t heard yet, Microsoft are running launch events for Visual Studio 2008, SQL Server 2008 and Windows Server 2008. And one of the best perks for going is, “you will leave with a promotional kit that includes product licenses for Windows Server 2008, Microsoft SQL Server 2008 and Microsoft Visual Studio 2008”

Check out http://www.microsoft.com/heroeshappenhere/events/default.mspx for details on all events or go straight to the Ireland events here, see you there ;-)


Your can register for the Belfast event here or you can register for the Dublin event here

posted on Thursday, February 28, 2008 1:05:22 PM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [1]
 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 [2]
 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]