Zero Friction: Creating a test model
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:
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.
Comments
Not so bad, I may adopt this!
BUT, a big but!
Why the redirection of ITextField and IButton.
edit.WebCastName.Value = newTestName;
Should be
edit.WebCastName = newTestName;
likewise
edit.Save.Click()
Should be
edit.Save();
I understand that you want to reveal your intent about making this look like user interaction. But this clearly break a LoD?
The model is a stupid representation of the page.
I want to be able to do more than just set values there, I need to interact with the page.
For example, I may want to type slowly and watch that the JS observer is doing its job, etc.
This looks a bit like the page manager model suggested for testing WebForms - see http://blogs.conchango.com/richardgriffin/archive/2006/11/14/Testing-Design-Pattern-for-using-WATiR_2F00_N.aspx
James Avery extended WatinRecorder to generate similar style models:
http://infozerk.com/averyblog/watin-test-recorder-watin-model-style/
Hey Ayende,
How about giving Stormwind.Accuracy a try? It's written on top of Watin (you could use any browser driver though).
It's really easy to use, and I guess you will find you don't need to remember the field names since you can specify a convention for the fields, like:
if you use "txt" as a prefix for Textboxes and you want txtUserName, in your test you would use "User Name" as the textbox name.
You should at least check it out... You might want to help us out get it improved!
You can check it out here: http://using.stormwindproject.org:8081/display/accuracy/Home
And you can check-out it here (lol):
http://svn.stormwindproject.org/svn/Stormwind.Accuracy/
Cheers,
Bernardo Heynemann
Developer @ ThoughtWorks UK
Comment preview