Testing the UI: presentation and rendering
I recently read Jeff Patton’s column at StickyMinds. His latest article tells us the secret to automated acceptance tests. I responded, and I include that response here.
I like this article, Jeff, but I’d like to point out that programmers can automate more tests in advance without risking a ripple effect when a customer wants to move a field around.
We know that many designs exhibit high coupling between “the UI” and “the logic”, and teasing that coupling apart—mostly moving (business) logic out of the UI—is one step towards more flexibility, less ripple effect and more valuable automated end-to-end tests. We have all seen it. I invite programmers to take one more step.
Inside “the UI” I find two major kinds of code: UI toolkit client code and more general toolkit-neutral code. When I format a monetary amount as ”$12.50”, I can make that decision without involving the UI toolkit; but when I decide to display the text ”$12.50” as a label or in a text field, I need to involve the UI toolkit in that decision. I invite programmers to separate their UI into presentation logic (UI toolkit neutral) and rendering logic (UI toolkit specific). If you do this, you will have an “abstract UI” or “presentation layer” you can test without drawing a real UI. These tests run quickly because they run in memory without having to paint a screen or invoke a UI toolkit component of any kind. You don’t need end-to-end tests here. When someone decides to move a field around, none of your presentation layer tests need to change, and you avoid the ripple effect. Yes, your end-to-end tests change, but over time you’ll automate fewer of those, preferring instead to automate the presentation layer tests.
So programmers, do your worst! Introduce a true presentation layer into your design, starting with the next screen or page. You’ll thank yourself, and maybe me.
JUnit Recipes coming soon to Safari Online
I would like to announce that Manning Publications has begun sending its books to Safari Online, the subscription-based O’Reilly service. I have found the service useful over the past three years, particularly after our flood wiped out much of my professional development book collection. If you subscribe to the service, but have not yet read JUnit Recipes, you will soon have your chance!
You're invited! "Test-Driven Enterprise Code" at XP 2008
Allow me to invite you to XP 2008 in Limerick, Ireland on June 11, 2008 at 2 PM local time to join me for Test-Driven Enterprise Code, my long-running tutorial aimed at programmers who want to practise test-driven development in the complicated world of platforms, frameworks, libraries, and more. Stay tuned to this channel for presentation slides, and possibly more.
Mercurial, Python, Mac OS X and duplication
As you all know, I’m not a fan of duplication. When we duplicate code we create safe, warm places for defects to hide. The more we duplicate, the more things go wrong, the harder they are to debug and, most importantly, the more we need to know in order to find the root cause of the problem. (In particular, we need to know we’ve duplicated something and where it is duplicated.) Just to emphasize that this is not some arcane theoretical notion about programming, allow me to share with you an adventurous half-hour I just spent trying to get mercurial (or hg, if you like) to play nicely between my MacBook Pro and my Mac Mini.
I have a working copy of a Mercurial forest in the same place on two different computers, one is my MacBook Pro and the other is my Mac Mini. When I have to do book-keeping work, I often use the laptop for handling paper and my desktop for running QuickBooks. This helps me avoid overworking either computer and that slowing me down. At least, this is my intent.
Since I’m using hg, by its nature a decentralized version control system, I have to be sure to keep my two working copies synchronized. This means periodic push operations from the laptop to the desktop or pull operations to the desktop from the laptop, depending on which keyboard happens to be in front of me at the moment. Since push from here to there and pull from here to there are essentially the same operation, it stands to reason that I should be able to do either one equally well.
I could push from the laptop, but not pull from the desktop. I was getting this error:
hobbes:Operations jbrains$ hg incoming ssh://mel.local/Workspaces/DiasparSoftwareServices/Operations remote: Traceback (most recent call last): remote: File "/usr/local/bin/hg", line 11, in <module> remote: from mercurial import demandimport; demandimport.enable() remote: ImportError: No module named mercurial abort: no suitable response from remote hg!
After some searching, I came across an article that suggested I had an ssh problem, and since I hadn’t swapped keys from the desktop to the laptop yet, I did that, hoping it would magically solve the problem. It did not. It saved me typing my password for each pull or incoming operation, but what other value it has, I don’t know. I had to search on.
After a few more minutes, I found this article, which suggested to me that my PYTHONPATH or PATH was wrong. I compared the environment variables on both computers and that wasn’t the problem. I compared the locations of Mercurial on both computers with a quick which hg and they were the same. I was beginning to think that I just didn’t know enough about installing Python packages to make this work, but then I asked each computer to locate mercurial.
Aha!
The laptop answered /usr/local/lib/python2.5/site-packages and the desktop answered /Library/Python/2.5/site-packages and there it is: the two environments expect Python packages in different places. I bet some symbolic links will do the trick.
On the desktop, I did this:
/usr/local/lib jbrains$ sudo ln -s /Library/Python/2.5 python2.5
Now when someone looks for Python packages in the usual UNIX place (/usr/local/lib/python2.5), the file system points them to the usual Mac OS place (/Library/Python/2.5@). I’m not thrilled about two different conventions, but as long as I can make one be like the other, it’s all good.
On the laptop, however, I found a defect as a result of duplication. I found Python libraries both in /usr/local/lib/python2.5 and in /Library/Python/2.5. It’s a wonder anything Python works correctly in that environment. This is the defect I fixed today. I moved the Python libraries into the usual Mac OS place (/Library/Python/2.5) before adding the same symbolic link that I’d added on the desktop.
And yes, folks, now it all just works. Mostly because now there’s only one place for Python libraries to live on each computer.
If you remove duplication, you don’t just improve the design, but you remove places defects can hide.


