WatiN Patterns #1: No Browser Left Behind
In my previous posts on WatiN, I lamented the shortage of online documentation and resolved to do something about it by documenting the patterns I’ve found for good WatiN tests. This is the first in a series in which I’ll take an example of the typical beginner WatiN test I see and refactor it to use the patterns I recommend.
Consider this test:
[TestMethod]
public void SearchPageTest()
{
IE ie = new IE();
ie.GoTo("http://www.google.com/");
ie.TextField(Find.ByName("q")).TypeText("Richard Lawrence");
ie.Button(Find.ByName("btnG")).Click();
Assert.IsTrue(ie.ContainsText("www.richardlawrence.info"));
ie.Close();
}
It has a few problems, but I want to highlight one in this post: This test doesn’t properly clean up after itself. If the code on lines 66-70 throws an exception or if the assertion fails, line 71 will never be executed. When you’re testing on your own machine, this can be annoying—you have to close the IE window manually. But if the test runs unattended (e.g. as part of continuous integration) it can be much more than annoying.
I’ve sometimes seen this attempt to work around the problem:
[TestMethod]
public void SearchPageTest()
{
IE ie = new IE();
ie.GoTo("http://www.google.com/");
ie.TextField(Find.ByName("q")).TypeText("Richard Lawrence");
ie.Button(Find.ByName("btnG")).Click();
bool resultsFound = ie.ContainsText("www.richardlawrence.info");
ie.Close();
Assert.IsTrue(resultsFound);
}
Introducing a local boolean to indicate success and closing the browser before the assertion ensures that the browser gets closed whether the assertion fails or succeeds. However, it won’t necessarily close the browser in case of an exception.
Fortunately, WatiN.Core.IE implements IDisposable, so you can do this:
[TestMethod]
public void SearchPageTest()
{
using (IE ie = new IE())
{
ie.GoTo("http://www.google.com/");
ie.TextField(Find.ByName("q")).TypeText("Richard Lawrence");
ie.Button(Find.ByName("btnG")).Click();
Assert.IsTrue(ie.ContainsText("www.richardlawrence.info"));
}
}
In case you’re not familar with the “using” statement, it’s a shortcut for this:
IE ie;
try
{
ie = new IE();
// whatever you're going to do with ie
}
finally
{
if (ie != null)
{
ie.Dispose();
}
}
At the end of the using block (or when an exception is thrown) ie.Dispose() is called, which closes the browser window.
Use this pattern in your WatiN tests to ensure that your tests clean up after themselves and leave no browser window behind.
A using statement is fine if you want to open and close a browser for every unit test. This will become very time consuming as the number of tests grow.
@Nick – True, as the test suite gets large, you may need to share a browser instance between tests (assuming browser start-up is the bottleneck for you). Tests shouldn’t have to worry about whether the browser is in a good starting state, though, so I usually recommend replacing IE with a class of your own that implements IDisposable and has an IE. That class would take responsibility for creating the IE instance when necessary in its constructor and resetting state in Dispose. Perhaps I’ll write about this in more detail sometime if there’s interest.
Also, since this post, I’ve changed from using WatiN with NUnit or MSTest to using it with Cuke4Nuke. This changes the patterns somewhat.