I’ve been thinking a lot about how to [tag]unit test[/tag] [tag]UI[/tag]s in [tag]C#[/tag]. There’s this trope that I hear again and again from developers: “Unit testing a user interface is nigh impossible.” I think anyone who has worked with thick client UIs(user interfaces) should go and have a looksee at the programs available for testing the user interaction with those UIs. Most of them rely on pixel-interaction and, on Windows, sending fake Windows messages directly to the message pump of the application being tested. Both of these methods seem error prone and like deadweights around the neck of an [tag]agile[/tag] process. In a sense, these kinds of heavy user interface tests are a rigid kind of documentation of a UI and not a very expressive one at that.
One of the things I like best about NUnit is that the unit tests become declarative statements about the units being tested and, by extension, the program itself. The unit tests become a sort of negative space around the map of the correct functionality of the units and serve to document those units in a very expressive way. Each small test not only gives the assurance of correct functionality but serves to define what that functionality is and explain it to the reader. The tests play multiple roles: as guarantees and as documentation. That is fantastic.
I think a tool that could help test UIs would also serve multiple purposes. I think that it would not only help define proper interaction and proper states but also help keep UIs standard across far-flung organizations.
So why isn’t there a tool like that for testing UIs? I think, in part, because people become wrapped up in the presentation of a user interface and forget that there’s a logical structure underneath it all, waiting to be exposed. I’ve heard many times that, “If only the UI was built more as an MVC then we wouldn’t have this problem.” Wrong. An MVC exposes a model in a view whose interactions are externally controlled, sure… but I don’t think this particular design pattern is flexible enough to simultaneously maintain proper UI state, make a programmer’s job easier, and enforce UI standards across an organization. We need something that will address all those at once.
Maybe a correct approach is to think of most UIs as a kind of state machine (or maybe several interlocking ones if that is simpler). Each piece of the UI mosaic contains state (enabled/disabled, checked/unchecked, valid/not valid) that relates back to the whole and can be used to draw conclusions about that whole (user can enter text here but not here, user can click there but not there, etc.). I think this state machine is separate from the model and the view and shouldn’t be in the controller at all. It should express concepts about the UI, and contexts about the UI, without specifying “button this” or “menu that”.
To segue a bit… I’ve also been using Spring, a very cool IOC/DI(dependency injection) tool, which has taught me that a simple shift in paradigm can reap enormous benefits. Utilizing Spring has made my development life much more pleasant: my objects are more testable, my interfaces more meaningful… in general, the app is much more flexible. By using Spring and adapting the code just a little bit I feel like the codebase has greatly improved.
In that way it is similar to Rails. All that Rails asks is that you, the developer, shift your focus a bit and follow some conventions. The leverage that it provides as a framework creates enormous productivity gains while the models it provides engender a paradigm shift in what I think is the right direction: less grunt work, more concept work.
Which all brings me back to my pie-in-the-sky UI testing guy (Rhyming is Good): Who wants to hand check every UI that the team produces to make sure that it is pixel perfect in order to match UI standards for a company? Who wants to spend time adapting UI tests because usability tests indicated that the buttons should be a bit narrower and shifted down a few pixels thus throwing off the auto-clicker UI tester? Who wants to spend concept time doing the grunt work of tracking down why the damn “Save” menu item is enabled when the user hasn’t dirtied the editing window yet? Man, not me.
So here we are. I think good UI unit testing has to follow these rules:
- Be a framework. Ask the developers to give up some ground and the maximum flexibility provided by their programming languages so that the framework can transmute a little prior knowledge into a big win at UI time.
- Enforce a logical context separate from the view, model, and controller. Consider that most languages that define UIs in thick clients smash together the view and controller by default (Windows forms, anyone?) and you’ll see that if this isn’t made drop dead simple most developers will fight it. Enforce the idea that the user’s interface exists in a logical space that is separate from anything found in UI control libraries.
- Declare and document functionality. Any UI tests should not just exercise the user interface but should also define it. Don’t just verify what it does, state what it does in a compiler-enforceable language.
- Enforce arbitrary standards. I should be able to define any wacko standards that I wish easlily and declaratively. They should be in code just like the tests themselves.