Zero Friction: Creating a test model

time to read 2 min | 333 words

I am writing some integration tests at the moment, using WatiN, and I am really enjoying the process. The last time that I tried to use WatiN it was in a WebForms environment, and it was... hard.

Using it with MonoRail is a real pleasure. Here is a simple test:

[Test]
public void Can_submit_new_values_for_webcast()
{
	browser.GoTo(appUrl + "webcast/edit/" + webcast.Id);
	var newTestName = "New test webcast name";
	browser.TextField("webcast_Name").Value = newTestName;
	var newDesc = "There is a new webcast description";
	browser.RichTextEditor("webcast_Description_Editor").Type(newDesc);

	browser.Button("webcast_save").Click();

	browser.Url.ShouldContain("webcast/view/" + webcast.Id);
	ReloadWebcastFromDatabase();
	webcast.Name.ShouldEqual(newTestName);
	webcast.Description.ShouldEqual(newDesc);
}

For a while, I was happy with this, but I have over two dozen such tests, and it is getting very annoying to remember what the all the names of all the fields are. The second time that I started copy & paste the ids from one test to another I knew that I had a big issue. How to solve this was something that I had to think about for a while, and then it came to me.

I can create a model for the interaction with the page, and test the UI through that. Here is my test model:

image Using that, I could get my test to look like this:

[Test]
public void Can_submit_new_values_for_webcast()
{
	browser.GoTo(appUrl + "webcast/edit/" + webcast.Id);
	var newTestName = "New test webcast name";
	edit.WebcastName.Value = newTestName;
	var newDesc = "There is a new webcast description";
	edit.Description.Type(newDesc);

	edit.Save.Click();

	browser.Url.ShouldContain("webcast/view/" + webcast.Id);
	ReloadWebcastFromDatabase();
	webcast.Name.ShouldEqual(newTestName);
	webcast.Description.ShouldEqual(newDesc);
}

Not that big deal, you may say, but now I can just blaze through those tests, writing them with far less friction along the way.

This is especially true when you modify the implementation of the page, but not the interaction, in this case, you want to be able to replace the implementation in a single place (say, change the id of a control, or the type of a control), instead of all over the place.

I am quite happy with this for now.