Industrial XP:  CommunityPage? IndustrialxpPractices StoryTestDrivenDevelopment UnitTestDrivenDevelopment Test First User Interfaces

Test First User Interfaces

Revision r1.2 - 13 May 2004 - 21:50 GMT - PhlIp

A mailing list to discuss testing hard situations:

http://groups.yahoo.com/group/TestFirstUserInterfaces/


Tests on GUIs should not display any windows. But programmers writing such tests should display them early and often.

Here's an example of TFUI in Ruby, using the TkCanvas?:

http://www.rubygarden.org/ruby?SvgCanvas

The source is not on that page, but it uses a function called maybeMainloop(), which should be called reveal().

Here's an example using Gtk+, and a function called reveal():

http://gnomesupport.org/wiki/index.php/TestDrivenDevelopment

(A lot of you are wondering "why not Java"? Because Ruby can look like Java, with typecasts added and block closures taken out.)

Here's the "Spigot" technique in Qt (C++ for Linux, KDE, and embeddings):

http://wiki.linuxquestions.org/wiki/Qt/TestDrivenDevelopment

Here's a near-TFUI sketch in Java, using HttpUnit?:

http://www.c2.com/cgi/wiki?HttpUnitTutorial

It uses reveal() to display today's Dilbert. (I recently introduced a Romanian programmer to the existence of Dilbert, leaving me feeling quite fulfilled and glowing...)

A lot of you are wondering "what's with the reveal()"?

This sample says it very succintly:

http://www.rubygarden.org/ruby?WebUnit

It uses Ruby and WebUnit?, which designs to compete with HttpUnit?. (I promise - if I wrote a project in Java I'd use HttpUnit?.)

A TFUI test case looks like this, in a hypothetical (but vaguely Ruby-like) language:

 def test_Window()
    win = CreateMyAppWindow()
    assert_equal("My App", win.GetTitle())

    # new code goes here

    # reveal(win)

 end

The call to reveal(win) is commented out.

(Those who miss Java can add a lot of 'private' and {} and redundant type declarations all around it. Don't get me wrong - I like Java. All its extra stuff make it a great language to illustrate refactoring with.)

If you de-comment reveal() and run the test batch, this window pops up, and control flow blocks until you close it.

If you dislike the window's appearance, add assertions before the reveal() call, and then program until you can see the window again. If you still dislike it, repeat.

If you approve of the window, comment out the reveal() line, and integrate. (Don't integrate with the reveal() line turned on!)

If you need to test how the window behaves when clicked-on, turn reveal() on, then click on the window. (If you reveal() from the bottom of a test that propels the window into an interesting state, you will see it fully populated with data, so you don't need to type that all in.)

After clicking on the window, comment the reveal() out, and then write more test code that does the same thing to your code as clicking on the window did. You might call your own callback method directly (yes, even if it is private). Or you might research, a little, to learn how to invoke your GUI Toolkit's event system for the clicked-on control.

Calling 'reveal()' to write automated tests that should not reveal their windows might seem like cheating.

It is.

Traditional GUI development couples to form painters (and debuggers) that couple programmer behavior to window appearances. Your cycle is paint->code->debug->paint. This cycle does what reveal() does for us, but at the wrong times. You paint when the controls are not populated, and you debug when they are manually populated.

Writing a test to call 'reveal()' takes control of this situation. We efficiently display the window exactly when we need need it. Form painters, debuggers, and even Web servers no longer control us.

When you develop a GUI, invent a reveal() function that works on any of your windows. Your teardown should destroy windows, whether displayed or not, so they don't bunch up in memory. You also should not have to "think" too much before typing reveal(win) and seeing a window. If your app needs temporary data or folders or whatever, or your windows are special and need a separate hardware screen, then work on reveal() to take care of all of this.

Put another way, if you are thinking about your window - and not about reveal() - then you should not have to think about anything to do with reveal() except typing it and running all the tests.


Some examples for various libraries:

-- PhlIp - 12 May 2004


TWiki home


Useful Links

· Edit this page
· IXP Community Page
· Print preview
· Recent Changes
· Advanced Options
· Register
· Change Notification