<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gojko Adzic &#187; automation</title>
	<atom:link href="http://gojko.net/tag/automation/feed/" rel="self" type="application/rss+xml" />
	<link>http://gojko.net</link>
	<description>Building software that matters</description>
	<lastBuildDate>Wed, 04 Aug 2010 11:38:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>When windows are not enough</title>
		<link>http://gojko.net/2007/08/21/when-windows-are-not-enough/</link>
		<comments>http://gojko.net/2007/08/21/when-windows-are-not-enough/#comments</comments>
		<pubDate>Tue, 21 Aug 2007 14:16:33 +0000</pubDate>
		<dc:creator>gojko</dc:creator>
				<category><![CDATA[articles]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[productivity]]></category>

		<guid isPermaLink="false">http://gojko.net/2007/08/21/when-windows-are-not-enough/</guid>
		<description><![CDATA[It&#8217;s not uncommon for &#8220;star&#8221; programmers to be an order of magnitude more productive than their colleagues. I believe that a large part of that productivity gap comes not from doing tasks faster, but from not doing them at all. Good programmers make the machine sweat instead. I recently had a very unpleasant talk with [...]]]></description>
			<content:encoded><![CDATA[<p><img align='left' src='/images/253568_clock_7.jpg' style='border:1px solid black; margin:5px 5px 5px 5px;' /> <i>It&#8217;s not uncommon for &#8220;star&#8221; programmers to be an order of magnitude more productive than their colleagues. I believe that a large part of that productivity gap comes not from doing tasks faster, but from not doing them at all. Good programmers make the machine sweat instead.</i><span id="more-40"></span></p>
<p>I recently had a very unpleasant talk with one of our support developers. She was very annoyed, in a defensive mood, arguing that she is already too busy and cannot take on a bit more work. After twenty minutes of talking, she finally calmed down, and we came to the root of the problem. It&#8217;s not the programming part of her work that is killing her, but the fact that she has to go through several terminal servers to deploy changes to client environments, and that she has to merge all her changes into several revisions. And she does that for every single change, several times a day. So, in fact, she spent most of her time logging on to different computers and copying files between them. Although she understood the problem herself, the thought of automating those silly tasks never came to her mind. </p>
<p>It&#8217;s incredible how, for a profession based around telling machines how to perform dull and error-prone tasks instead of humans, so few programmers think about how to automate their own work.  This is especially noticeable with the &#8220;Windows generation&#8221;, people who never effectively used the command line. GUI programs are, without a doubt, more user friendly and easier to use, but they are bloody hard to automate. When a task has to be done fifty times, or performed across the network, words &#8220;ease of use&#8221; take on a completely different meaning. That is the point when good programmers break from the usual practices and find better ways to do the job, and bad programmers stick to their old habits. </p>
<h2>Breaking from the old habits</h2>
<p>A few years ago, I did some consultancy work for a company whose application generated huge log files on clustered servers. To find the cause of any problem, programmers and support staff transferred gigabytes of data from client&#8217;s web servers to their computers in order to analyse them. Each transfer took at least 10 to 15 minutes. There was no special reason for pulling all the log files to local machines, people were just used to doing their job like that. I was even more amazed to see that even some &#8220;senior&#8221; programmers in that organization repeatedly (tried) to open monstrous log files in Notepad and than wasted the next 20 minutes waiting for their machine to unfreeze.  All that just to find a few lines of text, which could have been done in a minute or two using <i>findstr</i> on the server. </p>
<p>When a solution clearly does not scale to the problem, we look for a better one, or a different way to implement it. The solution often requires using a different approach, or different tools. The same holds for non-programming tasks. We must look for better ways to perform daily tasks when the usual tricks don&#8217;t work. In this case, the proper solution was to use the command line. Programs like <i>tail</i> and <i>grep</i> were developed at a time when network connections were bad, and computing power was scarce, so they don&#8217;t require a lot of typing and clicking.  Although available bandwidth and computing power have improved greatly over the last 20 years, such tools are still irreplaceable for processing large text files, especially on remote computers. Sadly, I meet more and more developers who never heard of those tools. If you are reading these lines and thinking to yourself &#8220;<i>what the heck is grep</i>&#8220;, here is just a brief introduction to some common tasks that these tools do really, really well: </p>
<blockquote>
<h3>grep</h3>
<ul>
<li>get all lines containing a string (or a regular expression) from a large file &#8211; for example, get all log items for a particular session or user</li>
<li>count the number of occurrences of a string (or regular expression) in a file &#8211; for example, find how many times someone has logged yesterday</li>
<li>find all files that contain a string (or regular expression) &#8211; for example, list log files that contain a particular username</li>
</ul>
<h3>more</h3>
<ul>
<li>view the start of a large file &#8211; for example, see the IIS log file format which prints column headers in the first line</li>
</ul>
<h3>tail</h3>
<ul>
<li>quickly view the last few lines of a large file &#8211; for example, check out the last exception</li>
<li>monitor how a log file is changing while other processes are writing into it &#8211; great for troubleshooting a live application, because it does not lock the file</li>
</ul>
<h3>awk</h3>
<ul>
<li>extract lines from a large file and reformat them &#8211; for example build URLs by appending fields from a tab-separated log file to the site prefix, or create a block of SQL statements to populate tables from some data export file</li>
<li>calculate statistics on file content &#8211; find top 20 client IPs by web bandwidth used and print the number of requests and total bandwidth used by each one</li>
<li>split a file into several other files, based on line content &#8211; for example, extract multi-line exceptions from a log file </li>
<li>quickly analyse a comma-separated, tab-separated or any other file format with multiple fields in a line</li>
</ul>
<h3>sed</h3>
<ul>
<li>&#8220;replace all&#8221; for large files and sets of files</li>
</ul>
</blockquote>
<p>Working on Windows is often an excuse for not using command-line tools, but that is just an excuse. There are several free sets of tools which bring power to the Windows command line. For example, <a href='http://www.cygwin.com/' target='_blank'>Cygwin</a> package allows most popular Unix tools to run from Windows. <a target='_blank' href='http://www.microsoft.com/downloads/details.aspx?FamilyID=9D467A69-57FF-4AE7-96EE-B18C4790CFFD&#038;displaylang=en'>Windows Resource Kit</a> from Microsoft contains <i>tail</i> and <i>qgrep</i> (a fairly usable variant of grep). <a href='http://www.microsoft.com/technet/sysinternals/utilities/pstools.mspx' target='_blank'>PsTools</a>, another package now owned by Microsoft, contains gems like <i>psexec</i> that can run a program on a remote computer. Some tools, like <a href='http://gnuwin32.sourceforge.net/packages/gawk.htm' target='_blank'>GNU Awk</a> have been directly ported to Windows by the GNU foundation. </p>
<p>On any variant of Unix, you can expect these tools to be already installed. Some trimmed-down replacements exist even for the standard Windows command line (like <i>findstr</i> which can be used instead of <i>grep</i> if you don&#8217;t look for regular expressions). However, most of these tools can just be copied to a remote machine and started (no need to &#8220;install&#8221; them), so you don&#8217;t require any special privileges to run them on client&#8217;s web servers, for example. You can just drop them on a remote computer and start using them. So don&#8217;t even try pulling the entire log file from the customers web site just to do a simple search: copy <i>gawk</i> there and process the log on the server.</p>
<p>In addition to being very efficient, these tools can easily be automated (scripted). It does not really matter whether shell scripts, batch files or some scripting language like vbscript, python or perl is used. Storing a <i>grep</i> or <i>awk</i> command line along with all the strange parameters will save you from the pain of writing them again tomorrow. </p>
<h2>Three strikes, and you are out</h2>
<p>&#8220;<i>Don&#8217;t repeat yourself</i>&#8221; is one of fundamental guidelines of Extreme Programming. Most good programmers today take care not to repeat the code, the ones that are even better find similarities in design and consolidate them, but very few apply the same rule to their habits or non-coding related work. I&#8217;m not just talking about half-hour tasks like sorting e-mail and analysing debug logs, but also small jobs like checking whether the client database is on-line or replacing seven occurrences of a field name in a script. </p>
<p>Apart from saving time, using <i>replace all</i> will also prevent errors, but you have to test it first before updating a 200 MB file on a client&#8217;s environment. The same tasks have to be applied for replacement in a 5 KB script file. There is always some overhead involved in automating the tasks, but when does it begin to pay off, and when is it unjustified? The rule I stick to is Roberts&#8217; rule of Three (from Fowler&#8217;s <a onClick="javascript:urchinTracker('/books/refactoring');"  target="_blank" href="http://www.amazon.com/gp/product/0201485672?ie=UTF8&#038;tag=swingwiki-20&#038;linkCode=as2&#038;camp=1789&#038;creative=9325&#038;creativeASIN=0201485672">Refactoring: Improving the Design of Existing Code</a><img src="http://www.assoc-amazon.com/e/ir?t=swingwiki-20&#038;l=as2&#038;o=1&#038;a=0201485672" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />), another version of DRY:</p>
<blockquote>
<h3>The Rule of Three by Don Roberts</h3>
<p>The first time you do something you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyway. The third time you do something similar, you refactor.
</p></blockquote>
<p>This is also a good rule of thumb for tasks outside of coding. Read it like this: If you catch yourself doing something for the third time, chances are that you will have to do it again, so automate it. Use the <i>replace all</i> if you have to replace the same string more than two times. More importantly, stick to the rule when things get complicated! If you are not dealing with plain strings, but have to re-format the data a bit, don&#8217;t fall back to manual work: utilise regular expressions (if you don&#8217;t know how to use regular expressions, <a href='http://www.gnu.org/manual/gawk/html_node/Regexp.html' target='_blank'>now is the time to learn</a>). If this is the third time this week that you are doing the same replacement, don&#8217;t use the regular expressions manually, but write a script. When you catch yourself running that script every day (week, month) add it to the scheduled tasks list (or cron jobs).</p>
<p>Automating tasks is especially important when your client has to perform them. Having a nice automated installer instead of a two-page word document explaining all the steps required to set up the software goes a long way. It makes the task less error-prone so the customers will be happier, and it leaves us with more time for the fun stuff.  </p>
<p>Image credits: <a href='http://www.sxc.hu/profile/dlee' target='_blank'>D Lee/SXC</a></p>
]]></content:encoded>
			<wfw:commentRss>http://gojko.net/2007/08/21/when-windows-are-not-enough/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Automating web tests with FitNesse and Selenium</title>
		<link>http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/</link>
		<comments>http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/#comments</comments>
		<pubDate>Sun, 20 May 2007 21:03:39 +0000</pubDate>
		<dc:creator>gojko</dc:creator>
				<category><![CDATA[articles]]></category>
		<category><![CDATA[fitnesse]]></category>
		<category><![CDATA[acceptance testing]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[selenium]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[UI]]></category>
		<category><![CDATA[webtest]]></category>

		<guid isPermaLink="false">http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/</guid>
		<description><![CDATA[Web user interfaces have traditionally been hard to integrate into an automated test process. Selenium+FitNesse combination, with just a bit of coding, solves this task incredibly well. Selenium is a free browser automation and testing library, written by folks at ThoughtWorks. It can simulate text input, mouse events and execute various tests on page content. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/images/731545_check_it_2.jpg" style="border:1px solid black; margin:5px 5px 5px 5px" align="left"/>Web user interfaces have traditionally been hard to integrate into an automated test process.  Selenium+FitNesse combination, with just a bit of coding, solves this task incredibly well.</p>
<p><a href="http://www.openqa.org/selenium-core/" target="_blank">Selenium</a> is a free browser automation and testing library, written by folks at ThoughtWorks. It can simulate text input, mouse events and execute various tests on page content. It&#8217;s written in JavaScript, and is compatible with all major browsers and platforms.</p>
<p><a href="http://www.fitnesse.org" target="_blank">FitNesse</a> is an open-source test and collaboration server, based on the <a target="_blank" href="http://fit.c2.com/">Framework for integrated tests (FIT)</a>, and supports testing Java, .Net, Python and even some other code. I think that it is a good choice for the second side of the web UI testing coin, because it enables tests to be written almost like in English language. As the UI is very close to clients&#8217; eyes, tests can and should be written so that clients can verify them (and if you are really lucky, even help with writing and maintaining the tests). <span id="more-53"></span></p>
<p><br clear="all"/></p>
<p><b>UPDATE: I wrote a follow-up to this article in Feb. 2008, focusing on testing AJAX applications. Read it on <a href="http://gojko.net/2008/02/14/ajax-selenium-fitnesse/">http://gojko.net/2008/02/14/ajax-selenium-fitnesse</a></b></p>
<h2>Installing Selenium</h2>
<p>The core of Selenium is written in JavaScript, and is compatible with all major browsers. The Selenium Remote Console provides the glue between a test browser and .Net, Java or Python code, and enables us to write and run Selenium tests from almost all popular test frameworks.</p>
<p>Just download Selenium Remote Console from <a target="_blank" href="http://www.openqa.org/selenium-rc">http://www.openqa.org/selenium-rc</a>. Unpack the files somewhere on your disk, and then start the server from the server folder of the package, by executing <em>java -jar selenium-server.jar</em>. The server starts on port 4444 by default, if that port is taken you can change it by adding <em> -port <b>number</b></em> to the command line. </p>
<p>Selenium works by embedding the test site, along with some control scripts, in a frameset web page. The control scripts are then used to automate the test page in the main frame, and execute various tests. That method of work will clash with browser security rules if both frames do not come from the same domain. Remote console can open Internet Explorer and Firefox with a security tweak to allow cross-domain scripting, but if you don&#8217;t want that, or want to use a different browser, then put Selenium JavaScript files into your web site. Download them from <a href="http://www.openqa.org/selenium-core/" target="_blank">http://www.openqa.org/selenium-core/</a>, and put the files from core folder in the archive into the selenium-server folder of your web site (so that RemoteRunner.html is available on /selenium-server/RemoteRunner.html).</p>
<h2>A quick test</h2>
<p>Let&#8217;s first do a quick test to make sure that Selenium RC is running correctly. We&#8217;ll start a browser window, go to Google, enter a search phrase and click on the Search button. I&#8217;ll do the examples in C#, but you can also use Java &#8211; interfaces are very similar. Create a new .Net project, add thoughtworks.selenium.core.dll as a reference (it&#8217;s in the dotnet folder of Remote Control installation), and then create this class:</p>
<pre>
using System;
using Selenium;
namespace SeleniumTest
{
    class Console
    {
        static void Main(string[] args)
        {
            ISelenium sel = new DefaultSelenium(
              "localhost", 4444, "*iehta", "http://www.google.com");
            sel.Start();
            sel.Open("http://www.google.com/");
            sel.Type("q", "FitNesse");
            sel.Click("btnG");
            sel.WaitForPageToLoad("3000");
        }
    }
}
</pre>
<p>Make sure that Selenium RC is running, close all open Internet explorer windows, and then execute the program. Selenium RC will open a new IE window (it may be minimised on start, but you will see a new button in the task bar), and then go to Google and execute a search.<br />
<center><br />
<a href="/images/webtest-s1.png" border="0" target="_blank"><img src="/images/webtest-s1.png" width="600" /><br />click for full-size image</a><br />
</center></p>
<p>Selenium window has three frames. Top-left enables the user to display the log and debug the execution by examining the DOM tree. Top-right frame displays the last four executed Selenium commands, which comes useful when troubleshooting tests. The page under test is displayed in the central frame.</p>
<p>The first line initialises a selenium console instance, connecting it to a remote console on localhost port 4444. </p>
<pre>
ISelenium sel = new DefaultSelenium(
"localhost", 4444, "*iehta", "http://www.google.com");
</pre>
<p>The third argument is a browser string, and *iehta is the code for security-tweaked Internet Explorer which allows cross-domain scripting.  Use *chrome for firefox with cross-domain scripting, or *iexplore, *firefox and *opera for Internet Explorer, Firefox and Opera without cross-domain security tweaks. You can also specify a full path to the executable instead of these special keywords. </p>
<p>The fourth argument is the URL to the selenium test site, and is really important only if you do not use cross-domain scripting, but want Selenium to run the scripts from the local domain. In this case, it will try to get the remote runner from http://www.google.com/selenium-server/RemoteRunner.html, but since Google is not hosting a Selenium installation, it will run the local scripts instead. In any case, this argument needs to be specified, so just set it to some live site even if you use cross-domain scripting (like in this case).</p>
<p>As you can guess from the names, method Type will simulate entering data from keyboard into a text field, and Click will simulate a mouse click.  We accessed the text field and the button by their names, q and btnG.  Selenium can also find elements by their ID (prefix it with “identifier=&#8221;), XPath expression (prefix it with &#8220;xpath=&#8221;), DOM path or a CSS property. See <a target="_blank" href="http://www.openqa.org/selenium-core/reference.html">http://www.openqa.org/selenium-core/reference.html</a> for more information on locators.</p>
<h2>Connecting from FitNesse</h2>
<p>FitNesse is really great for automating acceptance tests, and if you have not had a chance to play with it yet, I suggest reading through the <a href="http://www.fitnesse.org/FitNesse.UserGuide" target="_blank">online user guide</a> for testing Java code, or my tutorial <a href="http://gojko.net/FitNesse/fitnesse.pdf" target="_blank">Getting fit with .Net</a> for working in the .Net environment. </p>
<p>Instead of writing a new fixture type for every page or web site, we use a generic <a href="/fitnesse/webtest">WebTest</a> fixture. It extends DoFixture, so that other fixtures can be easily embedded into it (for checking the back-end data after a web script, or preparing the stage for the web test). Web test fixture allows the scripts to be described almost like English prose, like this:</p>
<blockquote><p>
User opens URL http://localhost:7711/login.aspx<br />
User types testuser into username field<br />
User types testpassword into password field<br />
User clicks on Log In<br />
Page reloads in less than 3 seconds<br />
Page contains text You have logged in
</p></blockquote>
<p>To achieve the best effect, the script must relate to what users see on the screen. However, that is easier said than done. Text fields, check boxes and buttons are all instances of the &#8220;input&#8221; element, and although text fields are mostly distinguished by name, buttons names are typically not important, and users only see the &#8220;value&#8221; attribute of a button. WebTest fixture looks for various combinations of attributes: for example, when searching for a button, it first looks for an input element with type equal to submit or button, and the name attribute matching the query. If no such element is found, it looks for similar elements, with value attribute matching the query. On the end, it looks for a button with matching ID. All these combinations are listed in the buttonLocators array in the code:</p>
<pre>
 public static readonly string[] buttonLocators = new String[] {
	"xpath=//input[@type='submit' and @name='{0}']",
	"xpath=//input[@type='button' and @name='{0}']",
	"xpath=//input[@type='submit' and @value='{0}']",
	"xpath=//input[@type='button' and @value='{0}']",
	"xpath=//input[@type='submit' and @id='{0}']",
	"xpath=//input[@type='button' and @id='{0}']"};
</pre>
<p>Although looking for an element by ID or name would be quicker, we intentionally use Xpath and add extra information, to catch errors caused by wrong element types. GetLocator method checks a list of XPath expressions and returns the first matching element from the active document, so UserClicksOn method is very simple:</p>
<pre>
public void UserClicksOn(String buttonCaption){
            instance.Click(GetLocator(buttonCaption, buttonLocators));
}
</pre>
<p>We use the same technique to put text into text fields, areas and password fields. An array of Xpath expressions is used to check for various combinations of valid element types and attribute values, and the first matching element is then passed to Selenium Type method. </p>
<pre>
public void UserTypesIntoField(String what, String where){
      instance.Type(GetLocator(where.Replace(" ", ""), textFieldLocators), what);
}
</pre>
<p>Because text fields will mostly be referenced by a name or ID, but users will see the text before the field on the page (and probably try to reference it with that), we also strip the blanks from the name. So the test script line:</p>
<blockquote><p>User types 10109 into security number field</p></blockquote>
<p>will correctly map into an element named “securitynumber&#8221;.</p>
<p>With web tests, we typically want to check if the result was correct and if the site was responsive enough, and Selenium method WaitForPageToLoad can be used to check if a page loads in any given amount of time. The API is a bit weird, as it expects a string containing the number of milliseconds. We wrapped that into this WebTest fixture call:</p>
<pre>
public void PageReloadsInLessThanSeconds(String sec){
            instance.WaitForPageToLoad(sec + "000");
}
</pre>
<p>On the end, we need a method to verify that page contents are correct. Selenium method  IsTextPresent can help with that:</p>
<pre>
public bool PageContainsText(String s){
            return instance.IsTextPresent(s);
}
</pre>
<p>We&#8217;ll also need to open a browser and set up the Selenium environment from the test fixture. To keep the test script format in english-like prose, we&#8217;ll use the following syntax:</p>
<blockquote><p>Start Browser *iehta with selenium console on localhost at port 4444 and scripts at http://localhost:7711</p></blockquote>
<p>In WebTest fixture, that is covered by the following method:</p>
<pre>
public void StartBrowserWithSeleniumConsoleOnAtPortAndScriptsAt
   (String browser, String rcServer, int rcPort, String seleniumURL){
            instance = new DefaultSelenium(
                 rcServer, rcPort, browser, seleniumURL);
            instance.Start();
}
</pre>
<p>On the end of each test, we need to shut down the browser, so that remote console does not run out of resources. For that, we&#8217;ll use the following method:</p>
<pre>
public void ShutdownBrowser(){
            instance.Stop();
}
</pre>
<p>With all that, the web test can be easily described with this FitSesse script:</p>
<p><center></p>
<div style="overflow-x:scroll;width:600px;border:1px solid black;text-align:left">
<pre>

!|webfixture.WebTest|

!|Start Browser|*iehta|With Selenium Console On| localhost| At Port |4444|And Scripts At|http://localhost:7711|

|User Opens URL|http://localhost:7711/login.aspx|
|User types|testuser|into|username|field|
|User types|testpassword|into|password|field|

|User clicks on|Log In|
|Page reloads in less than|3|seconds|
|Page contains text|You have logged in|

|Shutdown browser| 
</pre>
</div>
<p><a href="/images/webtest-s3.png" border="0" target="_blank"><img src="/images/webtest-s3.png" width="600" /><br />click for full-size image</a><br />
</center></p>
<h2>Ajax testing</h2>
<p>With web 2.0 pages, waiting for the page to reload before we continue testing is not the best choice. Selenium also supports<br />
waiting for a JavaScript condition. Remember that Selenium script is being executed in a different frame, so referencing DOM elements and JS functions in your test site page will not work straight away. Prefix the references with<br />
<em>selenium.browserbot.getCurrentWindow()</em> to get from the Selenium frame to your test page. Here&#8217;s an example: </p>
<pre>
instance.WaitForCondition(
  "(selenium.browserbot.getCurrentWindow().get_username()!=null)",
  timeout);
</pre>
<h2>Remote execution</h2>
<p>Selenium Remote Console will try to open a new browser session with different security settings, but under the profile of the current user (in fact, the user which started the remote console). This may cause problems when you already have an open browser on the same machine.  The workaround is to use a different browser for testing. For example, I use Firefox for normal browsing, so RC can start IE and play with it. But, there is a much better solution.</p>
<p>As the name suggests, Remote Console can run on a dedicated test server, and be accessed remotely. Any browsers that RC opens will run on that machine. That enables developers to work with browsers on their machines and run the tests, without clashing with test execution. It also enables us to re-use the same FitNesse scripts to check how various browsers are behaving, even on different platforms. Just separate the initialisation and browser shut-down into SetUp and TearDown scripts, and then create a couple of different test suites with different SetUps which will use various browsers and remote console installations. Then, use symbolic links to import scripts from one test suite into all others. You will maintain scripts in one place, and they will test multiple browsers and platforms.</p>
<h2>Extending WebTest</h2>
<p>WebTest currently supports two more interesting methods: PageURLIs(String s) and  UserSelectsFrom(String what, String where). The first allows you to verify the page URL (and test redirections). The second automates selecting an option from a drop-down menu (HTML select element), in the form of <em>User Selects NY from Countries</em>.</p>
<p>Feel free to modify and adjust WebTest to your needs. For start, see dotnet/doc/index.html in your remote control installation for more information on ISelenium interface. You can a add search by ID to the top of all locator arrays, so that tests run faster, but that will make them more error-prone. You will probably want to add a few different expressions to the textbox, button or select lists. If you add something which may be useful to others, please share it by writing a comment on the  <a href="/fitnesse/webtest/">WebTest</a> fixture page.</p>
<p>Photo credits:<a href="http://www.sxc.hu/profile/lusi" target="_blank">Sanja Gjenero/SXC</a></p>
]]></content:encoded>
			<wfw:commentRss>http://gojko.net/2007/05/20/automating-web-tests-with-fitnesse-and-selenium/feed/</wfw:commentRss>
		<slash:comments>50</slash:comments>
		</item>
	</channel>
</rss>
