Saturday, April 25, 2009

NCharlie: TDD – part 3 (a UI test)

In this post I tackle the last task on my list for the task manager search feature: “Write tests, then implement the ShowSearchResults method.”

In part one I wrote unit tests to verify my TaskManagerController class is listening (subscribed) to the SearchRequested event, and that it correctly responds by calling the TaskManagerView class “ShowSearchResults” method.  In part two I verified that the TaskRepository correctly returns tasks when the Search method is called.

I admit: as I write this sentence I’m not sure how I will accomplish writing a test to verify that ShowSearchResults works… so I posted the question to Twitter:

I wrote a unit test to verify my controller calls my view's "ShowResult" method... What kind of test verifies ShowResult shows the result?

…and got a reply from my boot-camp instructor:

@charliesolomon we automate testing the ui. don't know that there's a great name for that other than automated ui test. or just ui test.

@mhinze So at this point (UI testing) it is time for me to use WatiN or equivalent?

@charliesolomon yes, sounds like it.

So here I go… WatiN is an open source web application test framework for .Net that will spin up an instance of my web browser and verify things on a web page.  To verify that ShowSearchResults is working I want to verify that the correct search results display on screen when the ShowSearchResults method is called on the TaskManagerView.

TaskManagerSearch_2

First I create a new class library project named UITests.  I want to keep these tests in a separate project because they take much longer to run than my unit tests.  If I’m going to keep this example strictly “Test First”, I need to, well, write my test first:

[Test]
public void Should_show_search_results()
{
Task task = new Task("foo");
TaskRepository repository =
new TaskRepository(new HybridSessionBuilder());
repository.Save(task);

using (IE ie = new IE("http://localhost:1035/Default.aspx"))
{
Button search = ie.Button(Find.ById("btnSearch"));
search.Click();

Div tasks = ie.Div(Find.ById("tasks"));

Assert.IsTrue(tasks.InnerHtml.IndexOf("foo") >= 0);
}
}


I’m not showing the [SetUp] method here for this Test Fixture… it ensures I have a clean database before running this test.  The test above just adds a task to the database, fires up the web page and verifies the search results come up correctly.



Default.aspx is a very simple page… just a text field, button and repeater to show the results. The “ShowSearchResults” method is what I’m interested in implementing and testing for this feature.  For the sake of brevity in this post, I will just refer you to the code to see how the ASPX page and code-behind file are constructed.  Here is the ShowSearchResults method from Default.aspx.cs:



public void ShowSearchResults(ICollection<Task> tasks)
{
rptTasks.DataSource = tasks;
rptTasks.DataBind();
}



I run my test and see WatiN fire up Internet Explorer, click the “Get” button, then search the results for my test record…



watin-clicking-get



watin-showing-results



…and the Resharper test runner shows the results:



ui-tests-passed



That’s it!  Of course it looks really simple here, and it is… but it actually took me 3 hours to get this simple test working.  Here’s why:



NUnit uses multi-threading by default, WatiN requires a single-threaded execution.  I solved this using a config file (“NCharlie.UITests.dll.config”… naming this config file correctly was actually the biggest time sink for this exercise.  I ended up adding a test to check that my config file was being read – thanks Charlie Poole)



For more information, check out the tdd-demo code branch and see the WatiN getting started guide.



<< NCharlie: TDD – part 2 (an integration test)  TDD Pain Points, A Retrospective >>

No comments:

Post a Comment