Скачать 3.51 Mb.
What’s So Special about GUIs?
All GUIs solve the same problem: Users dislike keeping a program’s internal state in their heads. Projecting that state into pictures and animations leads to advanced and complex inputs. All GUIs collate elaborate input events from users, so all GUIs use an asynchronous event queue.
Asynchronous event queues are hard to test. But GUIs come with worse problems.
Why is TFP for GUIs Naturally Hard?
The target situation is this: We should be able to write new test cases that force predictable changes in a GUI’s appearance and response. Passing such new cases should upgrade a GUI. Each passing test raises our confidence that our GUI's appearance and response has improved, so we only rarely look at or drive the GUI.
All other libraries submit to program control, making prediction easy. But GUIs have a side only users see or touch. We don’t want to view the GUI after writing every test case, and we want to know that all tests constrain all our GUI features despite changes anywhere in a system.
Many tests call production code that sends a command to a GUI. Then the test queries the GUI to detect effects of that command. These tests might deceive when a GUI Toolkit supports asymmetric features. A program can change a graphic state, but can’t reliably read back that state. A program can simulate an input, but only as a programming convenience, not an accurate simulation that behaves the same as a real user.
We conquer these problems by enabling test cases that temporarily present GUIs, under test, for inspection and interaction. This, in turn, helps us grow test fixtures to increase the odds that we can predict GUI changes.
Why is TFP for GUIs Artificially Hard?
GUI Toolkits have steep learning curves. This inspires toolkit vendors to compete by using their toolkits to build helper applications—wizards, form painters, debuggers, etc. A good environment can flatten a GUI Toolkit’s learning curve, turning it from the hardest library in a project to the easiest.
So the GUI Layer, within a large project, may suffer neglect from much of a team’s total experience. We will call the backend of a project the Logic Layer. When this layer is mysterious, complex, and valuable, it often receives more senior attention, and more careful development practices. When leaders think that GUI development is “easy”, they might not pay so much attention to the growth of its design.
To put it indelicately, senior developers carefully write Logic Layers, and associate developers paint and debug GUIs. Chapter 14: Sluggo at Work, on page 453, illustrates this problem in disturbing detail.
GUI Toolkit vendors reinforce this culture. Their marketects claim, “Anyone can write simple data-entry forms with our system!” The fun starts as a team scales these simplistic forms up into rich and balanced applications.
A GUI’s windows and buttons are easy to see, so they are easy to specify. A Logic Layer is hard to see, so developers might work harder to design its code structure. When developers work too hard, the code can fill up with excess design elements, making it resist change in unexpected ways. This AntiPattern, “Big Design Up Front”, is the bane of much software engineering. GUIs typically have the opposite problem.
Much GUI development neglects design quality. Implementing new features by debugging muddy code until it just barely works leads to a familiar AntiPattern, “Code-and-Fix”.
Both AntiPatterns can generate code that resists unexpected changes.
GUI Toolkit vendors reinforce Code-and-Fix by promoting elaborate and tempting wizards and debuggers, to help you generate code you don’t understand, and then edit and debug it at the same time.
These interactive development environments often provide drag-and-drop interfaces to paint screens and wire up events. Such “design-mode interfaces” often obscure the techniques you need to bond controls to your test code.
TODO Test Code -> test code
Finding a way through these mazes, to write any test first, seems impossible.
When test cases target your specific application more more powerfully than generic form painters, debuggers, and wizards, GUI development becomes rapid and safe from bugs and unwanted feature creep. If your GUI Toolkit vendor used Test-First Programming, and bundled their Toolkit with a suite of exemplary tests (or all of them), your life is simpler. The rest of us are not so lucky.
How to Avoid TFPing a GUI?
Agile projects avoid extra work using a peculiar but effective strategy, often called “You Aren’t Gonna Need it”. If you predict you may have a problem, such as a thick GUI that requires tests, you don’t proactively solve the problem. Instead, you behave as if you don’t have the problem, and develop normally, while seeking opportunities to force the problem to appear.
The classic example here is optimization. You should write clear expressive code, and don’t prematurely obfuscate all of it on behalf of performance. (And you should use minor optimizations, such as const & in C++, that don’t obfuscate.) If your product must perform efficiently, you should frequently time-test your entire application. Only when performance degrades do you speed up the code. This strategy collects hard data first, to make certain you solve only the right problem. Making clean code fast is easier than making fast code clean. You don’t speculate, and make all the code faster; you right-size the effort, and only fix the code which your performance data shows is slowest. Notice that strategy implies you might store data tables in flat files until performance data indicate you need an expensive database.
Engineers seek ways to cause the problems they intend to solve. If they can’t cause a problem, they are done.
To avoid using the TFUI Principles, use standard TFP to write a module that does everything your GUI does, but uses no GUI controls. We will call this the Representation Layer. Mike Feathers has given that technique the nickname “Humble Dialog Box”, with this influential paper:
Anything a user can do to the GUI, a programmer can do to the module. If a user can click Submit, you have a Submit() method. If they can click on an element in a list box, you can pull a list of objects, and pass one into a corresponding function.
TODO TDDing -> TFPing
Anything the GUI can do to a user, this module does to programmers. If the GUI would disable that list box, then the programmer can detect the disability. If the GUI can refresh its display automatically when new data appear, the module can send a message using the Observer Pattern.
Now write the actual GUI, and make certain every event handler is as short as possible. It should do nothing but instantly delegate to the equivalent functionality in our wrapper module.
Other references might call our Representation Layer the “Logical User Interface”, or the “Presentation Layer”. A Representation Layer converts from one representation to another. Ours converts from the Logic Layer’s format to the user’s experience. We enforce our Representation Layer with a simple rule:
If your GUI Toolkit provides, say, Label, Form, and Pushbutton identifiers, your Representation Layer must not use any of them. This technique exposes your Representation Layer to the full benefit of logical design techniques without the encumbrance of GUI testing.
The Representation Layer converts database abstractions to user abstractions. Suppose the user can scroll a list box and select a name. The Logic Layer may or may not keep any names in any list. The Representation Layer re-arranges data to satisfy user needs.
|Dedicated to Ashley & Iris||Abramovitz, Janet N., and Ashley T. Mattoon. 1999|
|Plastics and the Environment. Hoboken. N. J. Wiley-Interscience. Ashley, S. 2002||Gilliland home is dedicated|
|Citations Acknowledging or using iris-related facilities and Data As of August 2010 Please send corrections and/or additions to||Dedicated to Jerry Lefcourt, Lawyer and Brother|
|Free to download magazine dedicated to Commodore computers||Morning session I: Dedicated to Prof. A. Acrivos, “Suspensions and particulates”|
|08: 30 Registration 09: 00 Welcome Remarks Morning session I: Dedicated to Prof. A. Acrivos, “Suspensions and particulates”||The Culture of Irises in the United States Iris Culture for the Mountain and Plains Region, D. M. Andrews 5|