The framework provides these libraries:
Entire Framework
(require (lib "framework.ss" "framework"))
This library provides all of the definitions and syntax described in this manual.
(require (lib "framework-sig.ss" "framework"))
This library provides the signature definitions:
framework^, and
framework-class^.
The framework^ signature cotains all of the
names of the procedures described in this manual, except
those that begin with test: and
gui-utils:. The framework-class^
signature contains all of the classes defined in this
manual.
(require (lib "framework-unit.ss" "framework"))
This library provides one
unit/sigs, section 41.3 in PLT MzLib: Libraries Manual:
framework@. It exports the signature
framework^. It imports the mred^ signature.
(require (lib "macro.ss" "framework"))
This defines the mixin macro. See section 3.2 for more information.
Test Suite Engine
(require (lib "test.ss" "framework"))
This library provides all of the definitions beginning with
test: described in this manual.
GUI Utilities
(require (lib "gui-utils.ss" "framework"))
This libraries provides all of the definitions beginning
with gui-utils: described in this manual.
The framework relies heavily on mixins. A mixin is a class
parameterization modeled on a paper published by Flatt, Felleisen, and
Krishnamurthi, available at
http://www.cs.utah.edu/plt/publications/icfp98-ff/.
The implementation of these mixins in MzScheme is with the combination of
lambda and class. The framework provides a macro to simplify
the checking and implementation of these mixins. Its syntax is very
similar to the syntax for class*, section 4 in PLT MzLib: Libraries Manual. The shape of
a mixin is:
(mixin (interface-expr ...) (interface-expr ...) instance-variable-clause ...)
This macro expands into a procedure that accepts a class. The argument passed to
this procedure must match the interfaces of the first interface-exprs
expressions. The procedure returns a class that is derived from its
argument. This result class must match the interfaces specified in the
second interface-exprs section; it has clauses specified by
instance-variable-clauses. The syntax of the initialization-variables and
instance-variable-clause are exactly the same as class*/names, section 4.3 in PLT MzLib: Libraries Manual.
The mixin macro does some checking to be sure that variables that the
instance-variable-clauses refer to in their super class are in the
interfaces. That checking and the checking that the input class matches the
declared interfaces aside, the mixin macro's expansion is something
like this:
(mixin (i<%> ...) (j<%> ...) clause ...) = (lambda (%) (class* % (j<%> ...) clause ...))
The i<%> interfaces do not appear in the output
because they are only used for the error checking and
are discarded by the time the class is created.
The mixin macro is provided by
(require (lib "macro.ss" "framework"))
The framework provides several new primitive functions that simulate user actions, which may be used to test applications. You use these primitives and combine them just as regular MzScheme functions. For example,
(begin (test:keystroke #\A) (test:menu-select "File" "Save"))
sends a keystroke event to the window with the keyboard focus and invokes the callback function for the ``Save'' menu item from the ``File'' menu. This has the same effect as if the user typed the key ``A'', pulled down the ``File'' menu and selected ``Save''.
It is possible to load this portion of the framework without loading the rest of the framework. See the libraries section for more details.
Currently, the test engine has primitives for pushing buttons, setting check-boxes and choices, sending keystrokes, selecting menu items and clicking the mouse. Many functions that are also useful in application testing, such as traversing a tree of panels, getting the text from a canvas, determining if a window is shown, and so on, exist in MrEd.
The actions associated with a testing primitive may not have finished when the primitive returns to its caller. Some actions may yield control before they can complete. For example, selecting ``Save As...'' from the ``File'' menu opens a dialog box and will not complete until the ``OK'' or ``Cancel'' button is pushed.
However, all testing functions wait at least a minimum interval
before returning to give the action a chance to finish.
This interval controls the speed at which the test suite runs,
and gives some slack time for events to complete.
The default interval is 100 milliseconds. The interval can be queried
or set with test:run-interval.
A primitive action will not return until the run-interval has
expired and the action has finished, raised an error, or yielded.
The number of incomplete actions is given by
test:number-pending-actions.
Note: Once a primitive action is started, it is not possible to undo it or kill its remaining effect. Thus, it is not possible to write a utility that flushes the incomplete actions and resets number-pending-actions to zero.
However, actions which do not complete right away often provide a way to cancel themselves. For example, many dialog boxes have a ``Cancel'' button which will terminate the action with no further effect. But this is accomplished by sending an additional action (the button push), not by undoing the original action.
Errors in the primitive actions (which necessarily run in the handler thread) are caught and reraised in the calling thread.
However, the primitive actions can only guarantee that the action has started, and they may return before the action has completed. As a consequence, an action may raise an error long after the function that started it has returned. In this case, the error is saved and reraised at the first opportunity (the next primitive action).
The test engine keeps a buffer for one error, saving only the first error. Any subsequent errors are discarded. Reraising an error empties the buffer, allowing the next error to be saved.
The function
test:reraise-error
reraises any pending errors.
Active Frame
The Self Test primitive actions all implicitly apply to the top-most (active) frame.
Thread Issues
The code started by the primitive actions must run in the handler thread of the eventspace where the event takes place. As a result, the test suite that invokes the primitive actions must not run in that handler thread (or else some actions will deadlock). See the eventspace section for more info.
Window Manager (Unix only)
In order for the Self Tester to work correctly, the window manager must set the keyboard focus to follow the active frame. This is the default behavior in Microsoft Windows and MacOS, but not in X windows.
In X windows, you must explicitly tell your window manager to set the keyboard focus to the top-most frame, regardless of the position of the actual mouse. Some window managers may not implement such functionality. You can obtain such an effect in Fvwm and Fvwm95 by using the option:
Style "*" ClickToFocus