Click here to Skip to main content
Click here to Skip to main content
Go to top

WatiN - Web Application Testing In .NET

, 8 Jan 2007
Rate this:
Please Sign up or sign in to vote.
This article exposes how to use WatiN and how to create UI tests for Web applications.

WatiN Test Screenshoot

Introduction

Nowadays, testing code is not so difficult. We have lots of tools that help us to achieve this goal. But in Web application development, we use to forget to test one of the most important layers, the UI. In this article, I'm going to briefly cover how to do UI and functional testing using WatiN (Web Application Testing In .NET). I'll try to show you what impressed me of this framework from a developer point of view.

What is WatiN?

WatiN stands for Web Application Testing In .NET, and it's a framework that enables web application testing through Internet Explorer. WatiN is inspired on WatiR, a web application testing framework for Ruby. The way that WatiN works is very "easy", knowing that there's a lot of work behind a framework like this. WatiN lets you open Internet Explorer instances, and through interop, interact with the elements in a form. With WatiN, you can get and set values from the elements in a form, and you can fire events of any of the elements in the document too.

Getting started

The API of WatiN is very user-friendly, and watching some code examples and digging a bit, you can get the benefit of this framework quickly. The first thing that we need to build a test method using WatiN is to add a reference to WatiN.Core.dll. WatiN gives us four namespaces; the one that we use to interact with IE instances is WatiN.Core. The different namespaces available are:

  • WatiN.Core.DialogHandlers: The namespace that provides the needed objects to manage the dialogs that the browser can show to the user. Some of the handlers you can find in this namespace are, for example: AlertDialogHandler, ConfirmDialogHandler, FileUploadDialogHandler, PrintDialogHandler, and LogonDialogHandler.
  • WatiN.Core.Exceptions: The namespace that hosts specific exceptions that would help us to control any unwanted behavior. Some examples of these exceptions are: ElementNotFoundException, IENotFoundException, TimeoutException, and a generic WatiNException.
  • WatiN.Core.Interfaces: The namespace that provides us some interfaces to extend the WatiN framework as, for example, the ILogWriter interface that lets us implement our own LogWriter class.
  • WatiN.Core.Logging: The namespace that hosts classes that will help us to log the actions that our code is doing. We can use the DebugLogWriter class to write log messages to the debug window, or we can use the Logger class to save our logs in other ways.

Because the scope of this article is introductory, I will only show you the usage of the most important objects of the framework. In order to learn more about the rest of the namespaces and/or objects, you can check the "References & Resources" section at the bottom of this article.

Now that we have a brief idea of what WatiN is and what we can do with it, let's write some code to see the API's usage.

using WatiN.Core;

[STAThread]
static void Main(string[] args)
{
    // create a new Internet Explorer Instance

    IE ie = new IE();

    // point it to http://www.google.com

    ie.GoTo("http://www.google.com");

    // fill the search box

    ie.TextField(Find.ByName("q")).TypeText("WatiN");

    // performs click event

    ie.Button(Find.ByValue("Google Search")).Click();
}

The above code example opens an Internet Explorer instance and points it to www.google.com, then, when the page is loaded, it searches a textbox with name "q" and fills it with the text "WatiN". Then, we do the same we did for the textbox but, this time, looking for a button whose value is "Google Search". In this case, we perform the "Click()" event of the button. If we run this console application, we will see an Internet Explorer opening and doing the things we coded. Isn't that cool?

Solving initial workarounds

Back into the previous piece of code, I have to mention a couple of things. In order to automate tasks with Internet Explorer, we need to run our test under a thread that has a single-threaded apartment (STA) as the apartment state. Notice that over the Main() method, we have the [STAThread] attribute that sets the apartment state to STA. A big question that I made myself when I came across this framework was, "And what about running this tests with NUnit?". NUnit doesn't run tests in a thread using the STA apartment state; it uses multithreaded apartment (MTA), but this isn't a big problem, so we can attach a config file to the NUnit test project and specify the apartment state mode that we want. Let's see how to do it:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="NUnit">
            <section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
        </sectionGroup>
    </configSections>
    <NUnit>
        <TestRunner>
            <!--<span class="code-comment"> Valid values are STA,MTA. Others ignored. --></span>
            <add key="ApartmentState" value="STA" />
        </TestRunner>
    </NUnit>
</configuration>

If we run the "Getting started" code sample, Internet Explorer will remain open after the actions we coded are performed. This will not affect us if we only want to run one test; we only need to close one Internet Explorer window. But if we want to run more than one test, we can do two things to avoid having to manually close the Internet Explorer windows. First, we can create the instance of the IE object using the using keyword and using the constructor that lets us specify the URL where the new instance will be pointed. If we do that, it gets closed and disposed after the test execution. Second, we can call the Close() method of the IE instance to programmatically close the window. Both are valid, but I prefer the first one because I think that the resulting code is more elegant than if we used the second one.

Creating our first UI test

If our test result is based on the response that the server sends back to the browser, we can parse the response in order to know if our test has failed or not. The way that we do that is exactly the same that we use to make the test, but searching other items in the page that help us to identify what happened. Suppose that we have an aspx page like this:

<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" >
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>WatiN Test Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <h2>Check if a nickname is already used</h2>
        <table>
            <tr>
                <td>Nickname:</td>
                <td><asp:TextBox runat="server" ID="txtNickName" /></td>
            </tr>
            <tr>
                <td colspan="2" align="right">
                    <asp:Button runat="server" ID="btnCheck" 
                                Text="Check !!" OnClick="btnCheck_Click" />
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <asp:Label runat="server" ID="lblResult" />
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

And now, suppose that we have this code on the btnCheck.OnClick event:

protected void btnCheck_Click(object sender, EventArgs e)
{
    // do some logic to check if the nickname is already used.

    // i'll return true for all nicknames but "gsus"

    if (txtNickName.Text != "gsus")
        lblResult.Text = "The nickname is already in use";
    else
        lblResult.Text = "The nickname is not used";
}

For writing these article code samples, I'm using Visual Studio 2005 running under Windows Vista, so I don't have Internet Information Services installed. For web development, I'm using the ASP.NET Development Server that came with .NET Framework 2.0, so in the next code sample, you will see that I start the Web Server programmatically in order to run the test. I think that this is a good way to decouple our UI tests from IIS. Now, let's see how the test looks finally:

using System.Diagnostics;
using WatiN.Core;
using NUnit.Framework;
using System;

namespace WebAppUITesting
{
    [TestFixture]
    public class UITesting
    {
        //process object 

        private Process p;

        [TestFixtureSetUpAttribute]
        public void SetUp()
        {            
            // create a new process to start
            // the ASP.Net Development Server

            p = new Process();

            // set the initial properties 

            string path = 
                   Environment.CurrentDirectory.Replace(@"WebAppUITesting\bin", 
                   string.Empty);
            p.StartInfo.FileName = "WebDev.WebServer.EXE";
            p.StartInfo.Arguments = 
                   String.Format("/port:8080 /path:\"{0}WebApp\"", path);
            p.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;

            // start the process

            p.Start();
        }

        [Test]
        public void CheckIfNicknameIsNotUsed()
        {
            // create a new Internet Explorer instance
            // pointing to the ASP.NET Development Server

            using (IE ie = new IE("http://localhost:8080/Default.aspx"))
            {
                // Maximize the IE window in order to view test

                ie.ShowWindow(NativeMethods.WindowShowStyle.Maximize);

                // search for txtNickName and type "gsus" in it

                ie.TextField(Find.ById("txtNickName")).TypeText("gsus");

                // fire the click event of the button

                ie.Button(Find.ById("btnCheck")).Click();

                // parse the response in order to fail the test or not 

                Assert.AreEqual(true, ie.ContainsText("The nickname is not used"));
            }            
        }

        [TestFixtureTearDownAttribute]
        public void TearDown()
        {
            // kill the ASP.NET Development Server process

            p.Kill();
        }
    }
}

As you can see, I use the method ContainsText in line 46. This method searches the specified text in the document content and returns a bool indicating if there are occurrences in the search. We can replace line 46 with the next code example, where we directly get the "lblResult" Span content to see if the nickname is already used:

// parse the response in order to fail the test or not 

bool result = (ie.Span(Find.ById("lblResult")).Text == "The nickname is not used");
Assert.AreEqual(true, result);

Conclusion

At this stage, we should know how to basically use WatiN framework to test web applications. I hope you find this framework and this article useful, as I did. Personally, I haven't used any other web application testing framework, but I got really surprised with how we can test our UI using WatiN. I think that we can do intensive UI and functional testing with it.

References & Resources

References:

Resources:

License

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

Share

About the Author

Jesus Jimenez
Web Developer
Spain Spain
Jesus Jimenez is a software development consultant in Madrid. He has focused in .Net technologies in the last years and he mainly works in ASP.NET environments. He is MCAD.NET since 2002 and is starting to be a bit paranoid about usability and user interfaces.
 
You can read his blog at: http://blogs.clearscreen.com/dtax

Comments and Discussions

 
AnswerRe: Access textfields in popup window Pinmemberjtg129-Oct-10 8:30 
QuestionCan I do a multi select using WatiN PinmemberAlpha_Male25-Nov-09 23:53 
GeneralUse WatiN to fill form fields in a running IE instance PinmemberFilipVW8-Aug-09 5:14 
AnswerRe: Use WatiN to fill form fields in a running IE instance Pinmemberjawed998641500610-Aug-09 23:18 
GeneralRe: Use WatiN to fill form fields in a running IE instance PinmemberFilipVW11-Aug-09 3:05 
GeneralRe: Use WatiN to fill form fields in a running IE instance Pinmemberjawed998641500611-Aug-09 23:27 
GeneralRe: Use WatiN to fill form fields in a running IE instance PinmemberFilipVW15-Aug-09 1:28 
GeneralRe: Use WatiN to fill form fields in a running IE instance Pinmemberjawed998641500615-Aug-09 9:49 
GeneralRe: Use WatiN to fill form fields in a running IE instance PinmemberMember 116639328-Jun-10 4:15 
GeneralWaitN -&gt; FireFox -- help [modified] Pinmemberskinflint6-Aug-09 22:59 
AnswerRe: WaitN -&gt; FireFox -- help Pinmemberjawed998641500611-Aug-09 0:13 
GeneralWatiN : Popup window and Radio button Pinmembersmita godbole27-Jul-09 9:19 
AnswerRe: WatiN : Popup window and Radio button Pinmemberjawed99864150063-Aug-09 2:06 
GeneralRe: WatiN : Popup window and Radio button Pinmembersmita godbole11-Aug-09 5:19 
AnswerRe: WatiN : Popup window and Radio button Pinmemberjawed998641500612-Aug-09 4:53 
GeneralRe: WatiN : Popup window and Radio button Pinmembersmita godbole17-Aug-09 4:41 
AnswerRe: WatiN : Popup window and Radio button Pinmemberjawed998641500617-Aug-09 5:58 
GeneralRe: WatiN : Popup window and Radio button Pinmembersmita godbole17-Aug-09 6:41 
GeneralRe: WatiN : Popup window and Radio button Pinmemberjawed998641500617-Aug-09 20:24 
QuestionHow can I find a link like this? PinmemberEric_Lee30-Jun-09 22:01 
Questionhow can i capture the button? PinmemberBobby.Wang30-Jun-09 21:52 
AnswerRe: how can i capture the button? PinmemberEric_Lee30-Jun-09 22:07 
QuestionCan WatiN accept inputs from an Excel sheet Pinmembervinay_fz7-Jun-09 18:52 
AnswerRe: Can WatiN accept inputs from an Excel sheet Pinmemberjawed998641500623-Jun-09 22:32 
QuestionHow to handle popup whose ID value in the URL changes each time the popup appears Pinmembervinay_fz15-May-09 19:27 
AnswerRe: How to handle popup whose ID value in the URL changes each time the popup appears Pinmemberutthesta923-Jul-09 6:20 
GeneralRe: How to handle popup whose ID value in the URL changes each time the popup appears Pinmembervinay_fz26-Jul-09 18:57 
AnswerRe: How to handle popup whose ID value in the URL changes each time the popup appears Pinmemberjawed99864150063-Aug-09 2:33 
QuestionHelp required in how to handle the click of a table column header link button which calls asynchronusly(uses AJAX) in WATIN Pinmemberkeshavjois15-May-09 7:16 
QuestionHow to pass Multiple Value to a Text Field Pinmembervinay_fz12-May-09 23:21 
GeneralJust IE Pinmembermbaocha9-May-09 20:23 
QuestionHow to handle javascript popup's Pinmembervinay_fz3-May-09 20:33 
AnswerRe: How to handle javascript popup's Pinmemberjawed99864150067-May-09 21:08 
QuestionHow to maximize window Pinmembervinay_fz3-May-09 20:12 
AnswerRe: How to maximize window Pinmemberjawed99864150067-May-09 4:16 
GeneralUsing watin in Nunit and have this error Pinmemberirvinia3-Feb-09 17:17 
QuestionHow to make ie view full screen and how to disable close button Pinmembersrinivasadithya20-Jan-09 6:40 
GeneralDynamic ID Pinmemberms_gigabyte5-Jan-09 0:38 
GeneralRe: Dynamic ID PinmemberBobby.Wang10-Feb-09 16:48 
QuestionMultiple Pop Up windows PinmemberPolarGator19-Dec-08 5:00 
AnswerRe: Multiple Pop Up windows PinmemberPolarGator19-Dec-08 5:37 
Generalhelp me!!!!!!!!!! Pinmembersiddhartha mukherjee5-Nov-08 22:24 
QuestionHow to capture the same button PinmemberBobby.Wang15-Oct-08 21:30 
AnswerRe: How to capture the same button PinmemberMember 476430711-Jan-09 5:26 
GeneralRe: How to capture the same button PinmemberBobby.Wang10-Feb-09 16:28 
QuestionRe: How to capture the same button Pinmemberjawed998641500613-Apr-09 23:47 
AnswerRe: How to capture the same button Pinmemberkaaskop8-Jul-09 10:12 
GeneralApartmentState setting to MTA and not STA PinmemberPolarGator27-Aug-08 4:30 
QuestionIssue finding links in a Telerik menu PinmemberMember 43334941-Jul-08 4:41 
QuestionPopup window in WatiN? PinmemberK_ahr9-Jun-08 3:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 8 Jan 2007
Article Copyright 2007 by Jesus Jimenez
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid