Unit testing is an integral part of the application design. Unit testing is applied at different levels of the application. In this article we will focus on the User Interface level unit testing. We will use WatiN to test our ASP.NET application.

Introduction:

Unit testing is an integral part of the application design. Unit testing is applied at different levels of the application. In this article we will focus on the User Interface level unit testing. We will use WatiN to test our ASP.NET application.

What is WatiN?

WatiN is a tool inspired from Watir (Don't worry I will write an article on Watir  very soon) to test web pages. WatiN stands for Web Application Testing in .NET.

What are we testing?

In this article we will be testing a simple ASP.NET page. The page will demonstrate an agreement acceptance scenario. The user will type his name in the TextBox, click the “I agree” checkbox and then press the submit button. This is a very simple page to test but after you are familiar with the workings of the WatiN framework you can apply the same concepts for testing large pages.

Here is the screen shot of our page:

 Testing the Agreement Page:

Add a class library project to your solution and make references to the testing tool (I am using MbUnit but you can use NUnit or VS Team Suite Test Project) and the WatiN library. You can download the WatiN library from the here.  

Here is the simple test which makes sure that the user has agreed the agreement.

[TestFixture(ApartmentState = ApartmentState.STA)]
    public class TestAgreementPage
    {
        [Test]
        public void test_can_accept_the_user_agreement()
        {             
            IE ie = new IE(ConfigurationManager.AppSettings["DefaultPageUrl"] as String);

            ie.TextField("txtName").TypeText("Mohammad Azam");

            ie.CheckBox("chkAgree").Checked = true;
           
            ie.Button("Btn_Agree").Click();

            Assert.AreEqual("Valid",ie.Span("lblMessage").Text);           
        }       
       
    }

The class is decorated with the TestFixture attribute which also makes sure that the tests are run in a Single Threaded Apartment state. This is because the test will launch the Internet Explorer.

The IE class contained in the WatiN library does the main work. IE class opens the Internet Explorer and refers to the HTML controls using their name or ID. The line ie.TextField(“txtName”).TypeText(“Mohammad Azam”) refers to the TextBox with the ID “txtName”. When the browser is launched WatiN will write the text “Mohammad Azam” inside the TextBox named “txtName”. This will be done right before our eyes and you would be able to see WatiN typing text into the TextBox. Then the CheckBox with the ID “chkAgree” will be checked. Finally, WatiN will press the submit button and the form is submitted.

If you run this test it will fail. This is because the Label named “lblMessage” is never set to “Valid”. Let’s do that in the page code behind.

 protected void Btn_Agree_Click(object sender, EventArgs e)
        {
                lblMessage.Text = "Valid";
        }

Now, if you run the test it will pass. But, something does not seem right. Let’s remove the following line from our test.

ie.CheckBox(“chkAgree”).Checked = true;

This means we are not going to mark the CheckBox as checked. If you run the test again it will pass. This is not right! The test should only pass when the CheckBox is checked. Let’s make a change to the code behind of the page.

protected void Btn_Agree_Click(object sender, EventArgs e)
        {
            if (chkAgree.Checked)
            {
                lblMessage.Text = "Valid";
            }
        }

Now, the test will only pass when the CheckBox is checked.

Programmatically Running the Web Server:

In the above example you will need to start your WebServer by either manually running the command line tool or by running the Web Application Project. But, sometimes you will want the unit test project to dynamically start a web server. Let’s check it out how this can be done.

First, if you want to start the ASP.NET internal server (WebDev.WebServer) then you can use command line to start it. The syntax is shown below:

WebDev.WebServer.exe /port:1950 /path: “C:\Projects\MyWebApplication”

You will need to be in the same directory where the WebDev.WebServer exists. By default it is located at:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\WebDev.WebServer.exe

Now, let’s use this information to start the server using unit tests. First, here is the required configuration saved in the configuration file (App.config).

<configuration>

  <appSettings>
    <add key="WebServerExePath" value="C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\WebDev.WebServer.exe"/>
    <add key="Port" value="1950"/>
    <add key="WebApplicationPath" value="c:\projects\demowatiN\demowatiN"/>
    <add key="DefaultPageUrl" value="
http://localhost:1950/Default.aspx"/>  
  </appSettings>
 
</configuration>

The BaseTestPage class will use this information to start the server and all the test classes will derive from the BaseTestPage class to use this functionality. 

Here is the complete code for the BaseTestPage class:

public class BaseTestPage
    {
        static Process server = null;

        static BaseTestPage()
        {
            if (Process.GetProcessesByName("WebDev.WebServer").Count() == 0)
            {
                string webServerExePath = (string)ConfigurationManager.AppSettings["WebServerExePath"];
                server = new Process();
                Process.Start(webServerExePath, GetWebServerArguments());
            }
        }

        public static string GetWebServerArguments()
        {
            string args = String.Format("/port:{0} /path:\"{1}\"",GetPort(),GetWebApplicationPath());
            if (String.IsNullOrEmpty(args)) throw new ArgumentNullException("Arguments is not defined");
            return args;
        }

        public static string GetPort()
        {
            string port = ConfigurationManager.AppSettings["Port"] as String;
            if (String.IsNullOrEmpty(port)) throw new ArgumentNullException("Port is null or empty");

            return port;
        }

        public static string GetWebApplicationPath()
        {
            string webApplicationPath = ConfigurationManager.AppSettings["WebApplicationPath"] as String;
            if (String.IsNullOrEmpty(webApplicationPath)) throw new ArgumentNullException("WebApplicationPath is null or empty");

            return webApplicationPath;
        }

      
    }

We used a static constructor to make sure that the process is not running. If it is not running we make a new process and start it else we use the old process. The GetWebServerArguments(), GetPort() and GetWebApplicationPath() are just helper methods to improve the readability.

Finally, you will derive all your unit test classes from the BaseTestPage class as shown below:

public class TestAgreementPage : BaseTestPage

Now, if you run your unit test project will start the WebServer and then run all the tests.

Conclusion:

In this article we learned how to unit test our user interface layer. Unit testing the user interface helps us to understand the requirements of the interface and quickly see the expected result based on the user input. If this testing is done manually then it might take a lot of time.