Skip navigation.

Testing your web UI using SWExplorerAutomation and NUnit

GUI test tools | NUnit | web testing tools
[textile]In my "previous posts about SWExplorerAutomation (SWEA)":http://www.testingreflections.com/node/view/2592, I addressed a couple of initial problems with getting "SWEA":http://home.comcast.net/~furmana/SWIEAutomation.htm to work on a specific configuration of machine.

Having got past that, I moved on to more interesting things... Specifically, using SWEA under NUnit.

I won't go into the detail of any of the SWEA main features since "Alex Furman":http://www.alexfurman.net does that better than me in his "Flash Demo":http://home.comcast.net/~furmana/SWExplorerAutomation.html and developer documentation available on the "SWEA home page":http://home.comcast.net/~furmana/SWIEAutomation.htm

When should you use SWEA? Well, there are so many different circumstances where it would be appropriate and many where it wouldn't... rather than guess your circumstances, I'll tell you about mine:

* Intranet Application - everyone in this organisation has to use Internet Explorer - so testing compatibility with other browsers isn't an issue;

* Client-side UI features are relatively rich, with various helpers for selecting items and populating fields. These UI features can't be exercised unless executed in a browser. These are the only things we are trying to test via the browser. For example, problem-domain tests are pointed at the 'Model' layer of the application (see Model View Controller pattern);

* We currently have no test-coverage of these UI features, which in past months have been known to break without us noticing until the end of the iteration;

* We are working in a Microsoft-centric organisation with Windows PCs and servers, an application written in C#;

* We are employing TDD and Continuous Integration using Nunit + Nant + CruiseControl for other tests and it would be of value to have all test-results aggregated in the CruiseControl build reports;

One thing we aren't trying to do is run these tests with every build. As test-coverage grows, the duration of each build will become unwieldy so the plan is to comment them out in the build script and have a scheduled task that will uncomment them at night and a force a build.

Enough of the context...

h2. SWEA Scenes

A scene is essentially an abstraction of the web-page, decoupling your test-code from the layout of the page and even the names/ids of elements. It is much like an 'object map' or GUI map' as used by many other GUI test tools. Elements on the page (i.e. in the scene) are called 'Controls'. If an input field (HtmlInput Control) is given a new ID or you change the position of the control in the DOM, the scenes allow you to change the element's definition in one central place - the SWEA Project File. You can further desensitise your tests from UI changes since scenes support identifying controls by ID, Name and SWEA also supports using Xpath to find an element in the page, e.g.:

%{color:blue;padding:1cm;}@//a[attribute::class="search_button"]@%

This finds an anchor with the class attribute of "search_button". Ideally, each element in the page will have a unique ID. This will make automating your tests that much easier.

It is up to you to define these scenes using the SWEA Designer which is a rich-client gui that facilitates the process.

!http://www.testingreflections.com/files/usrimages/SWEADesSmall.jpg!:http://home.comcast.net/~furmana/images/SWDesigner.png

Run-time identification of what 'scene' you are in is automatic, although you have programmatic control over this too. In your code, you can interact with scene controls like this:

%{padding:1cm;color:brown}@((HtmlInputText)(scene["QueryText"])).Value = "Software Testing";@%

h2. An NUnit Test Fixture using SWEA

How have I structured the Test Fixtures...

I thought I'd illustrate with an example using the "MSN Search":http://search.msn.com Search Builder (link underneath the text-box)... I have created two simple tests to illustrate the example, focusing on the Search Terms feature.

Firstly, I'll need a few things:

%{padding:1cm;color:brown}@using System;@%
%{padding:1cm;color:brown}@using System.Diagnostics;@%
%{padding:1cm;color:brown}@using NUnit.Framework;@%
%{padding:1cm;color:brown}@using SWExplorerAutomation.Client;@%
%{padding:1cm;color:brown}@using SWExplorerAutomation.Client.Controls;@%
%{padding:1cm;color:brown}@using SWExplorerAutomation.Client.DialogControls;@%

An important class is the ExplorerManager. As its name implies, it manages the Internet Explorer (IE) instance. To minimise test execution time, it is best to define this as a class-level object otherwise, with each test you will have to create a new explorerManager adding an unnecessary overhead to the test. Additionally, only DisconnectAndClose when you have finished with Internet Explorer. One of the slowest parts of the test can be loading IE for the first time so, when we load it, we want it to be available to all of the tests without having to start a new IE instance or find an existing instance to attach to... (normally, I'd prefix private or protected members with an underscore "_" but I haven't in this example):

%{padding:1cm;color:brown}@[TestFixture]@%
%{padding:1cm;color:brown}@public class QueryBuilderSearchTerms@%
%{padding:1cm;color:brown}{%

%{padding:2cm;color:brown}@private ExplorerManager explorerManager;@%

I like to assign the Controls (Html elements in the scene) to names that are more easily readable in the tests so I create these once at the class level:

%{padding:2cm;color:brown}@private HtmlInputText queryBuilderQueryText;@%
%{padding:2cm;color:brown}@private HtmlSelect queryBuilderSearchType;@%
%{padding:2cm;color:brown}@private HtmlInputButton queryBuilderAddToSearch;@%
%{padding:2cm;color:brown}@private HtmlInputText queryText;@%

There are some event handlers that come in handy. I'll talk about these more in a later post so, although I have included them in this example, I've left them empty for now):

%{padding:2cm;color:brown}@private static void explorerManager_DialogActivated(object sender, DialogScene dialogScene)@%
%{padding:2cm;color:brown}{%
%{padding:2cm;color:brown}}%

%{padding:2cm;color:brown}@private static void explorerManager_DialogDeactivated(object sender, DialogScene dialogScene)@%
%{padding:2cm;color:brown}{%
%{padding:2cm;color:brown}}%

%{padding:2cm;color:brown}@private static void explorerManager_Error(object sender, SWException errorException)@%
%{padding:2cm;color:brown}{%
%{padding:2cm;color:brown}}%

h3. TestFixtureSetup

Let's move onto the [TestFixtureSetup]. If you aren't familiar with Nunit, this attribute causes the associated method to be executed once at the start of the run of tests in the fixture (as opposed to [SetUp] which runs before each test method). Here, I'll create an instance of the explorerManager:

%{padding:2cm;color:brown}@[TestFixtureSetUp]@%
%{padding:2cm;color:brown}@public void Init()@%
%{padding:2cm;color:brown}{%
%{padding:3cm;color:brown}@explorerManager = new SWExplorerAutomation.Client.ExplorerManager();@%

I might need those event handlers (like I said, I'll come back to these in another post):

%{padding:3cm;color:brown}@explorerManager.DialogActivated += new DialogActivatedEventHandler(explorerManager_DialogActivated);@%
%{padding:3cm;color:brown}@explorerManager.DialogDeactivated += new DialogDeactivatedEventHandler(explorerManager_DialogDeactivated);@%
%{padding:3cm;color:brown}@explorerManager.Error += new ServerErrorEventHandler(explorerManager_Error);@%

Now, I want to start Internet Explorer:

%{padding:3cm;color:brown}@explorerManager.Connect(-1,ProcessWindowStyle.Hidden);@%

The parameter -1 tells the explorerManager to create a new IE instance and the second "ProcessWindowStyle.Hidden" (in System.Diagnostics) tells it to hide the window, so I don't have to watch the test each time it runs. While developing the test, you will want to see what happens so instead, you can use "ProcessWindowStyle.Normal".

I'll need my scenes (as described above) and I want to work only in one of them so I'll 'set the scene' as part of the fixture set-up, navigate to it (the URL is defined in the SWEA project file as part of the scene properties) and wait for the page to load:

%{padding:3cm;color:brown}@explorerManager.LoadProject("MSNSearch.htp");@%
%{padding:3cm;color:brown}@Scene scene = explorerManager["SearchWithSearchBuilder"];@%
%{padding:3cm;color:brown}@explorerManager.Navigate(scene);@%
%{padding:3cm;color:brown}@scene.WaitForActive(30000);@%

Notice that I have navigated straight to the view that has the Query Builder and not via the home page. This has trimmed several seconds off the test since I only load one page.

I also find the code easier on the eye if I assign more readable names to the Controls (as mentioned earlier):

%{padding:3cm;color:brown}@queryBuilderQueryText = ((HtmlInputText)(scene["QueryBuilderQueryText"]));@%
%{padding:3cm;color:brown}@queryBuilderSearchType = ((HtmlSelect)(scene["QueryBuilderSearchType"]));@%
%{padding:3cm;color:brown}@queryBuilderAddToSearch = ((HtmlInputButton)(scene["AddToSearchButton"]));@%
%{padding:3cm;color:brown}@queryText = ((HtmlInputText)(scene["QueryText"]));@%
%{padding:2cm;color:brown}}% %{color:green}@//End of [TestFixtureSetUp]@%

h3. Setup and TearDown

In these tests, I don't want a SetUp method but I have decided to have a TearDown method...

After each test, I want the query text value to be reset. I could do this by navigating to the scene but, in this case, I have decided that it will be faster if I just reset the Controls to their initial state. There is a more advanced approach to this by capturing the Controls' initial state and then using a Reset() method to restore all Controls but in this case, I'll simply reset the queryTextValue:

%{padding:2cm;color:brown}@[TearDown]@%
%{padding:2cm;color:brown}@public void Reset()@%
%{padding:2cm;color:brown}{%
%{padding:3cm;color:brown}@queryText.Value = "";@%
%{padding:2cm;color:brown}}%

You may prefer to take the hit and reload the page - it depends on what you are trying to prove with your tests. For maximum performance, you will attach to an existing instance. This will save loading and unloading IE with the execution of each Fixture... I can come back to that another time since there are other things to consider when taking that approach.

At the end of all of the tests, I want to unload IE (especially important if the test is run with IE being Hidden):

%{padding:2cm;color:brown}@[TestFixtureTearDown]@%
%{padding:2cm;color:brown}@public void Dispose()@%
%{padding:2cm;color:brown}{%
%{padding:3cm;color:brown}@explorerManager.DisconnectAndClose();@%

%{padding:2cm;color:brown}}%

h3. Tests

Tests can remain relatively simple. For example, if I want to verify that entering a value into the Query Builder's Query Text field and clicking the submit button 'moves' the text from the Query Builder Search Terms to the main Search Terms text-box, I might do this:

%{padding:2cm;color:brown}@[Test]@%
%{padding:2cm;color:brown}@public void TestQBTermsMovedToMainQueryText()@%
%{padding:2cm;color:brown}{%
%{padding:3cm;color:brown}@string textValue = "Software Testing";@%
%{padding:3cm;color:brown}@queryBuilderQueryText.Value = textValue;@%
%{padding:3cm;color:brown}@queryBuilderAddToSearch.Click();@%

%{padding:3cm;color:brown}@Assert.AreEqual(textValue,queryText.Value);@%
%{padding:3cm;color:brown}@Assert.IsNull(queryBuilderQueryText.Value);@%


%{padding:2cm;color:brown}}%

Or, to test that Query Builder Search Terms, once moved, are appended to the main Search Terms with a space between them:


%{padding:2cm;color:brown}@[Test]@%
%{padding:2cm;color:brown}@public void TestQBTermsAppendedToMainQueryText()@%
%{padding:2cm;color:brown}{%
%{padding:3cm;color:brown}@string textValue = "Software Testing";@%

%{padding:3cm;color:brown}@queryBuilderQueryText.Value = textValue;@%
%{padding:3cm;color:brown}@queryBuilderAddToSearch.Click();@%
%{padding:3cm;color:brown}@queryBuilderQueryText.Value = textValue;@%
%{padding:3cm;color:brown}@queryBuilderAddToSearch.Click();@%

%{padding:3cm;color:brown}@string expectedText = textValue+" "+textValue;@%
%{padding:3cm;color:brown}@Assert.AreEqual(expectedText,queryText.Value);@%

%{padding:2cm;color:brown}}%

I think you get the picture.

h2. In closing

Before using SWEA, however, there are at least two things to consider...

* Alex plans to make it shareware at some future date so there will be licensing fees, although he assures me that the fee will be 'reasonable'

* IE7 is on the horizon and I don't know much work Alex will need to do to ensure that SWEA continues to be a viable choice

So far, SWEA gets the thumbs up from me. It is clearly a well thought out approach and, if you are working in a Microsoft-oriented organisation or project then it seems ideal. No need to "bridge .NET and WATIR":http://www.hanselman.com/blog/CommentView,guid,ed8a9800-0bf5-44e8-9442-cef92ae39a48.aspx to test your web-based UI.

I have noticed a few stability related issues with the designer and will advise Alex of them as and when I find them... "Alex has been increadibly responsive so far":http://www.testingreflections.com/node/view/2719#comment-984.

On the horizon, Alex plans to include support for showModalDialog(), treating it in much the same way as a Dialog, which for many will prove to be very useful - an affordable (we hope) UI test tool with an Object/GUI map and support for showModalDialog()...

Oh... and if you are worried about Visual Studio licenses... you don't need it (although it helps).

To try out SWEA using C#, all you need is notepad and the .NET SDK. If you still want some IDE support, try "SharpDevelop":http://www.icsharpcode.net/OpenSource/SD/Default.aspx it's Open Source and suitable for just this sort of thing... especially with its built in NUnit Test Runner (although I still prefer using the NUnit GUI)...

In later posts, I intend to discuss other features that Alex has given us such as handling javascript alerts and more. Then I intend to focus on maximising test performance, including a look into using "Cassini":http://msdn.microsoft.com/msdnmag/issues/03/01/CuttingEdge/default.aspx so that the tests can be completely self contained and provide access to mocked system components.

You can download SWEA from "http://www.AlexFurman.net":www.AlexFurman.net along with a comprehensive API reference and an easy to use quick-start guide.

%{color:grey}This is my personal experience of SWEA. Use it at your own risk. You should always perform your own evaluation before adopting a new tool or framework.%

Web Testing with C# or VB.NET

InCisif.net is an automation tool designed to implement client-side functional testing of web
applications under Internet Explorer 6.x or 7.x, using the C# or VB.NET language
with Visual Studio 2003, 2005 or Visual Studio Express Edition 2005.

Frederic Torres
(http://www.InCisif.net)
Web Testing with C# or VB.NET

File not found exception

I had the same problem but got it to go away by:
  • Setting Visual Studio Start Mode to Program
  • Putting the path to Nunit gui in the Start Application (C:\Program Files\NUnit 2.2.8\bin\nunit-gui.exe)
  • Then for command line arguments give just the name of the project file (MyProject.exe.csproj)
  • set the working directory to the project directory (C:\ProjectFolder\MyProject\)(N.B. not \Debug or \bin!!).
It seems to be related to a bug in nunit that cannot set the working directory correctly. I am using NUnit 2.2.8 so maybe it will be fixed in a later version.

SWEA does all of that...

[textile]The Scene designer allows you to do all of that... but once you have configured the Scenes you can hand-craft the code...

You could consider combining SWEA with "FitNesse":http://fitnesse.org but you will have to write some Fit Fixtures to use the SWEA library... I did that for a client recently... depends on your coding skills as to how feasible that might be for you.

Without knowing the context you are operating in and your programming skills/abilities it is difficult to advise.

Antony Marcano

Start with the basics...

[textile]Hi Sherine,

SWEA doesn't provide that feature (last time I checked)... Personally, I wouldn't want to do that. I prefer to hand-write the code and run the tests from within the IDE or in the NUnit GUI... The recorder is useful to learn the API but that's all I ever used the recorder for.

Antony Marcano

Web Testing Tools

Hi Antony,
I wanted to ask you if you can recommend some web testing tools for me to use. I need a free tool that visually identifies the controls of a web page and where i can put certain inputs in these controls. then a test report is displayed with which tests passed and which failed. If there are no free tools available :( then please tell me about the best and the cheapest tools.
Thanks a lot for your help!
Really appreciated!

Nunit and SWEA

Hi Antony,
I tried using Nunit with SWEA, it is working fine with me; but, i have a question if i record scripts using the SWEA, is there a way to view the script results directly through using nunit??

NUnit & SWEA

Hi Antony,

I have posted this with NUnit as for some reason it keeps wanting to pick it up from the obj directory. If I copy the assemblies to the obj directory it works and if I point Nunit to the bin directory it works however it doesn't retain this setting.

Sourceforge link: https://sourceforge.net/tracker/index.php?func=detail&aid=1412498&group_id=10749&atid=210749

Will post back when the permanent solution is resolved.

Cheers,
kele.

So...

Check that SWExplorerAutomation reference properties has Copy Local is True.

SWExplorerAutomationClient isn't in the GAC so you will need it in your output folder... (e.g. bin\debug) so change the Copy Local property on the SWExplorerAutomationClient.dll in your references for the project then rebuild...

Antony Marcano

Issue getting SWExplorerAutomation with NUnit

Followed your example and also Alex Furman's site. I created and Project and script and generated the C# code and it all works well. Then I created a Class Library referencing NUnit and SWExplorerAutomationClient and followed your example above. When I go to NUnit and run the Test but NUnit fails and it brings back:

TestCalc : System.IO.FileNotFoundException : File or assembly name SWExplorerAutomationClient, or one of it dependencies, was not found.

Any ideas?

Kele.

Comment viewing options

Select your preferred way to display the comments and click 'Save settings' to activate your changes.