Sunday, 30 September 2007

TDDing Web applications: requirments vs implementation details

Now that my Asp.Net testing framework release is getting closer, it's time to think how we could incorporate it into our TDD precess. Specifically, I'm interested in the Red-Green-Refactor pattern.

Suppose I'm trying to develop a site map with a tree-like structure. How do I test the output? In the world of domain logic, or even WinForms UI, the result is more or less well-defined by user requirements: we have to display a table of search results, for example. There's still "more or less", however: we could use a DataGridView, or a third-party grid, or use the form's OnPaint event and draw the results manually. This is what Presenters are for: the actual output is the implementation details, the Presenter is what we test for the search results. In most cases, binding the data to the UI is so trivial that we don't have to test it.

With the HTML output, it's different. Retrieving the data is one thing, but my current task is to display it. So, I reformulate my story: my control has to display a hierarchic data "properly". Here "properly" means proper indentation for items that are deeper in the tree. Purely visual concept, absolutely untestable.

So, I come with several choices. Usually I think of the Asp.Net controls as a high-level structure, and the raw HTML output as the implementation details. So, in other situations, I'd prefer to test the high-level structure. For example, I don't care much if my DataList renders as a table or a set of spans, but I want to make sure that the first Item's DataItem is what I expect it to be. The DataList is a part of a user story, and the HTML output is private implementation details.

With the Web UI development, it's different. Looks like any decision we make is upfront design. Anyway, there are two choices, basically. I can expect some nested DataLists, or Repeaters, or a TreeView, but now this becomes the implementation. Or I can expect some HTML. And the more I think about it, the more I prefer HTML. Now, HTML remains implementation if you think in visual terms. Should I make a bullet list, a set of DIVs, or a table? After all, even a "b" tag will behave like a list item if you apply an appropriate CSS style. But many tags carry a semantical meaning, and if we look this way, the answer is obvious: since we have a list of items, let it be a list tag!

There's also a "purist" approach: you define your own tag, TDD your HTML structure, and apply CSS wisely to satisfy your customer. But the point is, you choose the raw output for testing.

Now that we know what to test, we write a test, and the Red phase is finished. At the Green phase, we just override the Render method and write what we need to make the test pass. At the Refactor phase, we could notice that we use a foreach loop and refactor it into a Repeater, or we could use a server HTML control and build it programmatically, etc. Each way, the refactoring would work only if we haven't hardcoded the entire HTML string into our test. We started with a semantic meaning of the list, let's keep it this way. For example, we can store the output in an XML document, and ignore the node attributes and extra tags like spans and such. Also note that all these server controls appear not as a part of upfront design, but at the refactoring phase, which is what we really want for a TDD process.

Looking at the whole picture, we discover something we didn't expect: our implementation details became a part of a user story, and vise versa. To tell you the truth, I didn't expect the proven TDD principles working in a new field (who said they should?), but they did!

No comments: