1.1 What is JDemo?
1.2 What is JDemo not?
1.3 What can JDemo be used for?
1.4 JUnit as Role Model
1.5 Differences between JUnit and JDemo
1.6 When to write a Demo
1.7 Installing JDemo
1.8 How to write a Demo
1.9 How to run a Demo
1.10 GUI Demos
1.11 More about JDemo
2.1 Example application
2.2 Demos for the application
2.3 Demos for multiple purposes
3.1 Basic Framework Interfaces
3.2 Demo Execution and Life Cycle
3.2.1 Standard Demo Execution
3.2.2 Demo Execution States
3.2.3 GUI Demo Execution
4.1 Choosing an Appropriate Base Class
4.2 Class Hierarchie
4.3 AbstractDemoCase
4.3.1 API Description
4.4 PlainDemoCase
4.4.1 Example Usage
4.5 DemoCase
4.5.1 API Description
4.5.2 Example Usage
4.6 GuiDemoCase
4.6.1 API Description
4.7 AwtDemoCase
4.7.1 API Description
4.7.2 Example Usage
4.8 SwingDemoCase
4.8.1 API Description
4.8.2 Example Usage
4.9 LookAndFeel with SwingDemoCases
4.9.1 API Description
4.9.2 Example Usage
4.9.3 Comments
4.10 SwtDemoCase
4.10.1 API Description
4.10.2 Example Usage
5.1 Launching
5.2 Usage
6.1 JDemo Wizards
6.2 JDemo Launch Type
6.3 Misc
6.3.1 Recreate Demo Suite
6.3.2 Go to Referring Demos
7.1 Demo Identifier
7.2 Capturing Textual Output
7.3 Capturing File Output
7.4 Making Screenshots
7.5 Ant Tasks
7.5.1 Capturing Text Output
7.5.2 Capturing File Output
7.5.3 Making Screenshots
7.5.4 Known limitations
7.6 Image processings
7.6.1 Generic image processings
7.6.2 Composing images
8.1 Automated conversion from demos to tests
8.2 Peculiarities with demo-tests
8.3 Evaluation
9.1 JDemo Annotation
9.2 Example
10.1 JDemo CVS
10.2 Writing your own DemoRunner
10.3 Integrating the DemoRunner into other Applications
11.1 Batch Capture
11.2 Executing Sequences of Demos
Markus Gebhard
markus@jdemo.de
http://www.jdemo.de
Date | Author | Version | Changes |
---|---|---|---|
8th January 2005 | Markus Gebhard | 1.2 | 1. Adjusted all chapters to the new JDemo 1.2 version. 2. Added an index to the PDF version. 3. Adjusted version number to release. |
2nd September 2004 | Markus Gebhard | 0.5 | Minor corrections, added a new item to the future development chapter. |
16th August 2004 | Markus Gebhard | 0.4 | Adjusted examples to the new JDemo 1.1.1 version. |
23rd July 2004 | Markus Gebhard | 0.3 | Adjusted all chapters to the new JDemo 1.1.0 version. |
8th May 2004 | Markus Gebhard | 0.2 | 1. Added a chapter about a typical usage scenario 2. Added a chapter about demos as unit tests 3. Modified all other sections to fit the current JDemo release |
18th October 2003 | Markus Gebhard | 0.1 | First public version |
1.1 What is JDemo?
JDemo is a new demonstration framework written in and for the Java (Java is a trademark or registered trademark of Sun Microsystems, Inc. in the U.S. or other countries.) programming language. Its concept and implementation is based on the open source regression testing framework JUnit (http://www.junit.org) by Erich Gamma and Kent Beck. Although being quite different from JUnit, there are a lot of similarities.JDemo provides a uniform and straightforward way for writing code snippets similar to unit testing code. The code snippets can be used to demonstrate both the code usage and the output of the program - either to the screen, to a file or just as plain text. Furthermore the demo code can be used for documentation purposes.1.2 What is JDemo not?
JDemo is not an extension to JUnit. As will be described in the following sections, there are fundamental differences in the concepts of both frameworks. Also JDemo is not a substitute for unit tests. In fact using JDemo in practice for a while has shown that using both, JDemo and JUnit side by side, makes a perfect combination.Finally JDemo is not an academical project. On the contrary, most of the framework has been developed while working on serious (well, and also some not so serious...) projects. It has evolved and has already proven to be very useful for many purposes. Now that it is almost grown up, I want to share it with the open source community.1.3 What can JDemo be used for?
Being both very simple and flexible, JDemo has multiple benefits. Here is a list of the most important ones I have found:The list could be extended, but I think it is now time to explain the framework and show how to write a simple demo. Before that, I want to explain what the idea of JDemo goes back to though.
- Interactive testing
Writing demos for GUI components enables developers to run the dialogs they are working on, without having to start the whole application. They can pick a single component or a whole frame at a time - whatever is appropriate. This saves a lot of time and simplifies test driving the user interface or any other part of the application.- API improvement
Just like with unit tests, the demo code is written from the point of view of a developer who uses a given API, or - when writing the demo before the code - who is about to design the API. This will most likely lead to a better API.- Decoupled code
Writing code snippets, only demonstrating a small piece of the code, requires a more modular code design. This most likely leads to better decoupled software components.- Code documentation
When done with some care, the demo code demonstrates usage of the production code by providing simple code snippets. Those are a valuable resource for documenting proper usage.- Easier Library evaluation
When you are looking for a specific component for your GUI (graphical user interface), for example, it is much easier to start the demos for a given library to evaluate it, than to write your own code to fire up the library. Most commercial libraries come along with sample applications or other kind of proprietary demonstration code. Using a uniform way for writing and running demonstration code like with JDemo makes it much easier for developers to find out whether the library fits their needs and how it must be used.- Reduced code duplication
The JDemo framework classes provide a lot of convenience methods, so the developer does not have to care aboutmain
methods, creating application frames or whatever. Obviously this leads to fewer code duplication.- Automated creation of documentation
Each demo has a unique identifier that can be used to automatically run the demo, e.g. from within an Ant (http://ant.apache.org) build script. The output can automatically be captured either as text, as file or as a screenshot in case of GUI demos. This enables software developers to provide an automatic and reproducible way of creating up-to-date screenshots or sample output for the user manual. (Now doesn't that sound pleasing in a time where most manuals are already out of date when finished?)1.4 JUnit as Role Model
One day in early 2003 I found myself writing a JUnit test method that was not really meant to be an automated test, but rather a little piece of code making some kind of graphical output, I was interested in. I was tempted to use the unit test approach because I already had some code for initializing my software library in a unit test. By adding a few lines likeThread.sleep(10000)
andframe.show()
to the test and starting the TestRunner I was able to test drive the program and evaluate its output.For those being familiar with JUnit, it is obvious that using unit tests for interactive testing just does not make sense. Unit tests are meant to be run and evaluated automatically. Each test is only run once and all tests in the selected test suite are being run. This other kind of test code - from now on called demo code - requires a slightly different approach. All demos in a suite must be presented to the user, who then can arbitrarily pick a demo to be executed. It depends on his intention, what the demo is used for: If he is a developer working on the code, he probably wants to run the demo in order to actually see that the demonstrated program part behaves in the right way. As a developer who is looking for a code library, he probably wants to see if the library fits his needs or how its API can be used. With these totally different aims it is clear that demos are different from tests and mixing up demo and test code must be avoided.However there are a lot of advantages regarding the simplicity and the concept of writing unit tests, so I decided to make JDemo similar to the approved JUnit framework.1.5 Differences between JUnit and JDemo
Developers familiar with unit testing will only have to learn a few things in order to use JDemo.
Here is a list of the main aspects and differences one has to be aware of:
- Demo method names start with
demo...()
rather than withtest...()
.- In demos there are no
assert...()
statements. Each demo method must contain a call to ashow...()
method instead.- Demos are not run automatically but rather presented to the user in a hierarchical view. The user can pick and start the demos arbitrarily.
- Demos are not meant for ensuring the implementation to work as specified, but rather to demonstrate the code usage and the output to the user.
- Test cases and test suites in JUnit are analogous to demo cases and demo suites in JDemo.
- Demo cases can implement
setUp()
andtearDown()
methods, that (just as in JUnit) will be executed before/after the demo method.- Executing all demos in a demo suite at once does not make sense (in most situations), so demo suites in difference to test suites can not be run.
1.6 When to write a Demo
There are some situations indicating that it is a good idea to write a demo:
- Whenever you are tempted to write a
main
method, although you are not writing an application.- When you are developing a program or library and want to see some output without starting the whole application.
- Whenever you want others to see how to use your API. Writing demo code that actually works and is being maintained leads to very useful documentation, always being up to date. I know that this is also being claimed for unit test code, but I found that demo code is much more useful here.
- Whenever you want to be able to automatically generate program output, e.g. for documentation purposes.
1.7 Installing JDemo
Before writing the first demo, you will have to install the framework. Fortunately JDemo installation is simple:That's it.
- Download the distibution package from the JDemo homepage.
- Unzip it to a new directory.
- Add
jdemo.jar
to yourCLASSPATH
.
Advanced users can reduce dependencies: Thejdemo.jar
consists of the smaller librariesjdemo_core.jar
andjdemo_runner.jar
. Both of them are contained in the download package, too. At compile time you only will need the core library. When executing demos you will also need the runner library. The Eclipse plugin (see chapter 6) for example contains a runner itself, so Eclipse users will only need the core library.1.8 How to write a Demo
Similar to unit tests, demos are public methods nameddemo
...()
. They must be implemented in subclasses of one of the demo case implementations provided by the framework (e.g.de.jdemo.framework.DemoCase
). Demo methods must not have any parameters and their return type must bevoid
. They may declare to throw any kind of Exception, although a valid demo should never throw any (unless it demonstrates how to throw an Exception...).The probably most simple demo is a hello world demo:
This trivial demo class contains a single demo that will print out "
public class HelloWorldDemo extends de.jdemo.framework.DemoCase {
public void demoHelloWorld() {
show("
Hello World"
);
}
}
Hello World
" when being run. Note that the name of the demo is derived from the method name, so our first demo's name is "Hello World".1.9 How to run a Demo
There are various ways for starting a demo. One is to call a JDemo runner from the command line. The command
will start the demo above by using the Swing based runner contained in the JDemo library. Note that JDemo has to be installed as described in section 1.7. Figure 1.1 shows the DemoRunner after executing the Hello World demo.java de.jdemo.swingui.DemoRunner HelloWorldDemo
An alternative way for running a demo is to provide the code for starting the DemoRunner in themain
method of the demo class itself:
Note that this is not the recommended way for starting the DemoRunner: Directly referencing the DemoRunner from within a demo class adds lots of dependencies. The decision about what runner application to use should be made by the user at run time, not by the developer at compile time.
public static void main(String[] args) {
de.jdemo.swingui.DemoRunner.run(HelloWorldDemo.class);
}
Rrunning one or more demos from within an integrated development environment might be much more convenient - at least when there are plugins or extensions for JDemo being available and installed. For the popular Eclipse IDE, for example, there is a plugin available (see chapter 6).1.10 GUI Demos
Besides the text basedDemoCase
class, JDemo also contains demo case base classes providing convenience methods for GUI demos using AWT, Swing and SWT (for a complete overview of the available demo case base classes refer to section 4.1.For example, imagine you have written the code for a Swing GUI componentMyDice
, showing the top side of a die.Here is what a valid demo for this class could look like:
The demo class subclasses
public class MyDiceDemo extends de.jdemo.extensions.SwingDemoCase {
public void demo6Dice() {
JComponent diceComponent = new MyDice(6);
show(diceComponent);
}
}
de.jdemo.framework.extension.SwingDemoCase
because it uses a Swing component for output. Note that there is no need to care about adding the component to aJFrame
orJDialog
. TheSwingDemoCase
class does all the work for you in the providedshow(...)
method.Figure 1.2 shows what you will see when running the demo.
Now lets imagine your dice component also has a default constructor (without a parameter) for creating a die with a random number. It is a good idea to also provide a demo for that by adding a second demo method to theMyDiceDemo
class:
Running the DemoRunner will now present two demo cases to the user. Figure 1.3shows example screenshots.
public void demoRandomDice() {
show(new MyDice());
}
The complete source code for this and other simple examples of JDemo usage can be found in the examples folder of the JDemo download package.1.11 More about JDemo
This overview was meant for giving you an idea of what JDemo is all about. However there is a lot more to learn about it. So read on to the next chapters for a more detailed description of the framework and its API.
2.1 Example application
Let us have a look at a typical software application as shown in Figure 2.1. In order for the main application to start, you have to successfully log in at a login dialog. The main application frame consists of a tree, a list and a few other components. From there you can start a wizard for importing some files. Once there are files imported into the application you can move on to an export dialog that in the end creates a html file.![]()
Figure 2.1: Draft of a typical software application
Obviously the application can be divided into separate parts (and I am pretty sure this structure will also be reflected by the modules or packages in the implementation):During development most of the time software developers will work on one of these parts without caring much about the others. This is also true for unit tests, which are meant for testing small units of code. But what about the dialogs? If I want to see the html export dialog I have to start the application, log in, import files, etc. I have to navigate the whole way through the application until I finally see it on the screen. Of course the same procedure has to be performed if I just want to have a look at some example html output.So all that I want is some simple way to demonstrate certain parts of the application. But when looking into software engineering books I cannot find a single sentence about this kind of code demonstration.
- the login dialog
- the main application frame
- the import wizard
- the html export
2.2 Demos for the application
JDemo provides a consistent way for writing and organizing code for demonstrating parts of a software application. So for the application described in the previous section we would write a demo for the html export dialog, for example. Using theSwingDemoCase
class described in section 4.8, the demo might look somewhat like this:At first some example data is being created. Then the export dialog is being created using this data and it is being shown by calling a convenience method in
public void demo() {
ExportableData data = createExampleExportData();
ExportDialog dialog = new ExportDialog(data);
show(dialog);
}
SwingDemoCase
. The demo method contains everything being neccessary for demonstrating the export dialog - and nothing else.As we also want to see what the html output looks like, we continue writing a demo for showing some example output:The code uses some convenience methods from the
public void demo() throws IOException {
File outputFile = createTempFile("
.html"
);
ExportableData data = createExampleExportData();
new HtmlFileExport().export(data, outputFile);
show(outputFile);
}
DemoCase
class described in section 4.5 for creating and showing a temporary file.Now these two code snippets and others are then being arranged into suites of demos. The suites from each software module on their part can be arranged in another suite and we will end up with a tree of demos as shown in figure 2.2.
From now on for each part of the application there is a demo available. In the next section we will see what they can be used for.2.3 Demos for multiple purposes
Figure 2.3 shows what demos are useful for in the various phases of software development.![]()
Figure 2.3: Field of applications for demos in various phases of software development
The most interesting fact is that demos are not only useful during implementation, but also for deployment and maintenance.
This chapter has not been finished and will be extended in a future version of this document.
3.1 Basic Framework Interfaces
Figure 3.1 shows the base interfaces of the JDemo framework. As you can see, demos use the composite design pattern.IDemoCase
objects are actual demo implementations. Each demo has a unique identifierDemoIdentifier
consisting of the fully qualified demo class name and the demo method name. Demos can be aggregated inIDemoSuite
objects.![]()
Figure 3.1: Base interfaces of the JDemo framework
Compared to the JUnit framework there are two main differences:Figure 3.2 shows the interface of the
- The common superinterface
IDemo
does not provide any means for starting the demo. This is because it does not make sense to start a complete suite of demos at once. OnlyIDemoCase
implementations are supposed to be executed. The common superinterface ofIDemoCase
andIDemoSuite
is only there in order to be able to compose the demos into a tree structure.- There is no method to run a
IDemoCase
object directly. The reason is that running demos has proven to be more complex than running tests. So instead of a simplerun
method for executing the demo, there is aIDemoCaseRunnable
object being created, that takes care of the execution process.IDemoCaseRunnable
. The runnable carries information about the current state of the demo it has been created on. The framework contains a typesafe enumeration implementationde.jdemo.framework.state.DemoState
for the execution states. Section 3.2.2 describes the various states of a demo. A demo runner application can attachde.jdemo.framework.state.IDemoStateChangeListener
objects to the DemoCaseRunnable in order to react on state changes (see figure 3.2). When the demo has crashed, thejava.lang.Throwable
object that describes the problem can be requested using thegetThrowable()
method.![]()
Figure 3.2: The runnable for executing a demo case.
Being aRunnable
, it can be started in a separate thread and execute the demo. Theexit()
method is being called from within the DemoCase or the runner for normal demo termination. If the user requests to cancel the demo from outside (for example by pressing a stop button in the demo runner application), thecancel()
method is used instead to interrupt execution.3.2 Demo Execution and Life Cycle
This section describes the execution of demos in JDemo using the DemoCaseRunnable introduced in the previous section.3.2.1 Standard Demo Execution
Figure 3.3 shows the simplified sequence diagram of the execution of a demo (Note: Please don't mix up theDemoRunner
and theDemoCaseRunnable
: TheDemoCaseRunnable
is the default implementation of theIDemoCaseRunnable
interface described in the previous section, whereasDemoRunner
is a different class, that initiates the execution of a demo.) .![]()
Figure 3.3: Sequence diagram of demo execution.
Demo execution is separated into two steps:
- 1. A DemoCaseRunnable is being created
In order not to interfere with other demo executions, the DemoCase is cloned before creating a runnable. The runnable is then being created on the clone and attaches itself to the clone as its runnable. This tight coupling of DemoCase and DemoCaseRunnable is necessary because for GUI demos it must be possible to exit the demo execution from inside the demo code.- 2. The created DemoCaseRunnable is being run
The DemoRunner invokes the methodrun
on the DemoCaseRunnable. In the current framework implementation the DemoRunner actually creates a new thread on the DemoCaseRunnable and starts it. However for simplification this is not shown in figure 3.3.The DemoCaseRunnable then takes control of the demo execution process. After calling thesetUp()
method in the DemoCase, the actualdemo
...()
method is being executed. Finally the demo is terminated by callingtearDown()
.Note that for "symmetry" with JUnit test cases thesetUp()
andtearDown()
methods inDemoCase
are protected and can not be called from the DemoCaseRunnable directly. So the public delegate methodsexecuteSetUp()
andexecuteTearDown()
are invoked instead.3.2.2 Demo Execution States
During execution, each demo goes through a number of states. For implementing or running demos you will not have to care much about the different states. However, for a better understanding of the framework we will have a look at them.
Initial
After being created the DemoCaseRunnable's state is INITIAL. At this moment the runnable holds a new clone of the DemoCase object and none of the DemoCase's code has been executed (besides static initializers and the constructor).Starting
The state is set to STARTING before thesetUp()
method of the DemoCase is being called.Running
Right before calling the actual demo method, the state is changed to RUNNING. It stays running until the demo finishes or crashes.Finished
A demo is FINISHED as soon as thetearDown()
method has been executed. Usually thetearDown()
method is called by the DemoCaseRunnable right after when thedemo
...()
method returns. However this is not true for GUI demos (Refer to the next section for a detailed explanation regarding the differences in GUI demo execution).Crashed
If at any time of execution anError
or anException
is thrown from within the demo code, the state changes to CRASHED. The DemoCaseRunnable will then try to calltearDown()
in order to exit the demo.3.2.3 GUI Demo Execution
The execution of GUI demos is a little bit more complicated than the execution of standard demos described in the previous sections. This is because usually a demo with graphical output will show a window on the screen. When returning from itsdemo
...()
method, the window is still visible and the demo should be considered running until the window is being disposed.The DemoCaseRunnable described in the previous sections does not care about that special case. It simply exits the demo by callingtearDown()
right after returning from thedemo
...()
method. So there is a different implementationGuiDemoCaseRunnable
necessary for GUI demos. Figure 3.4 shows a simplified sequence diagram for the execution of an AWT or Swing GUI demo.![]()
Figure 3.4: Sequence diagram of GUI demo execution.
TheGuiDemoCase
has to know what window has been made visible in thedemo
...()
method. For this theshow(Window)
method delegates toregisterDemoWindow(Window)
. Here theGuiDemoCase
attaches aWindowListener
to the window being shown. Before returning from thedemo
...()
method, theGuiDemoCase
makes the window object visible. TheGuiDemoCaseRunnable
considers the demo still being running and does not exit the demo. Once the demo window is being disposed, theWindowListener
of theGuiDemoCase
catches awindowClosing
-event and requests theGuiDemoCaseRunnable
to exit the demo.
Note that a window object being passed to theregisterDemoWindow(Window)
method is called a managed window. Any GUIDemoCase
implementation should ensure that the window being shown is managed. The sections about the various GUI DemoCases in chapter 4 will explain how to achieve this. Otherwise theGuiDemoCaseRunnable
cannot handle state changes correctly. Also other features like changing the LookAndFeel (see section 4.9) and creating screenshots (see section 7.4) will not work.Finally note that for exiting a GUI demo from within the demo code itself (for example when the user hits a button) you can directly call the methodexit()
in theGuiDemoCase
class to dispose the window and exit the demo.
4.1 Choosing an Appropriate Base Class
Depending on what kind of software output you want to demonstrate, you have to choose one of the base classes provided by the framework. Table 4.1 gives a quick overview of what base class you should pick for your demo.
What kind of output shall be demonstrated? Appropriate base class Plain text ( java.lang.CharSequence
)de.jdemo.framework.DemoCase
File objects (e.g. *.html
,*.rtf
)de.jdemo.framework.DemoCase
Direct output to a hardware device
(e.g. Soundcard, LPT-Port)de.jdemo.framework.PlainDemoCase
Components from the Java AWT
(e.g. java.awt.List)de.jdemo.extensions.AwtDemoCase
Components from Java Swing
(e.g. javax.swing.JTable)de.jdemo.extensions.SwingDemoCase
Components from the IBM Eclipse SWT de.jdemo.extensions.SwtDemoCase
Table 4.1: Base classes to choose for various purposes
Each of the base classes provides convenience methods for demo implementations. They are described in the following sections and in the JDemo JavaDoc API.4.2 Class Hierarchie
Figure 4.1 shows the inheritance hierarchie of all demo case base classes provided with JDemo. Along with the base classesPlainDemoCase
andDemoCase
(for showing files and plain text), there are three gui demo case classesAwtDemoCase
,SwingDemoCase
andSwtDemoCase
. All those classes are described in the following sections.![]()
Figure 4.1: Inheritence hiearchie of the DemoCase base classes in JDemo
4.3 AbstractDemoCase
AbstractDemoCase
is the abstract base class for all demo case implementations. It contains basic implementations and convenience methods. You will not have to care about this class, unless you want to implement a new type of demo case base class.4.3.1 API Description
protected void exit();
This method can be called from inside a
IDemoCase
to send a request to theIDemoCaseRunnable
to exit the running demo. As for now calling this method only makes sense for GUI demo cases. This has been described in section 3.2.3.
public void cancel();
This method will be called from the DemoCaseRunnable to send a request to the
IDemoCase
to cancel its execution. Subclasses can overwrite this method in order to e.g. dispose a window. This method should not be called from inside a demo method itself.
4.4 PlainDemoCase
PlainDemoCase
is the most simple implementation of theIDemoCase
interface. It only implements the methods already described in the previous sections.You should choose this class as superclass for your demo if the output of your demo does not belong to the ones supported by the other base classes described below. This is most likely the case if your demo makes output directly to a hardware device like a soundcard, a printer or a robot connected to the serial port.4.4.1 Example Usage
Here is an example of aPlainDemoCase
demo playing a simple sound using theToolkit.beep()
method from AWT:
public class PlainDemoCaseUsageDemo extends PlainDemoCase {
public void demoToolkitBeep() throws Exception {
Toolkit.getDefaultToolkit().beep();
Thread.sleep(500);
Toolkit.getDefaultToolkit().beep();
}
}4.5 DemoCase
DemoCase
is another implementation of theIDemoCase
interface. It provides convenience methods that can be used in demo implementations for showing files and plain text:![]()
4.5.1 API Description
protected File createTempFile(String suffix);
This convenience method creates a temporary file with the given suffix (=file name extension, e.g. ".txt"). The file will be deleted when the virtual machine terminates.
protected void show(File file);
Tries to open the given file by passing it to the operating system. This is useful for example if the output of the demo is a *.html file or any other kind of binary. The method passes the file's name to the operating system which hopefully will open the file using the default application.
Note that this might not work properly on some systems. In fact at the moment it only has been implemented for Windows systems. The implementation for file launching can be found in
de.jdemo.util.FileLauncher
.
protected void show(CharSequence text);
Shows the given text (
java.lang.String
implements thejava.lang.CharSequence
interface). By default the text is printed toSystem.out
. The Swing based demo runner however shows the text in a dialog window instead.
4.5.2 Example Usage
In the examples directory of the JDemo distribution there is a classde.jdemo.examples.DemoCaseUsageDemo
containing example demos using theDemoCase
API. Here is an excerpt from this file:
public class DemoCaseUsageDemo extends DemoCase {
/*
*
Demo creating a temporary file and opening it using the convenience method.*
/
public void demoShowFile() throws IOException {
File file = createTempFile("
.html"
);
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
bw.write("
<
html>
<
head>
<
/head>
<
body>
"
);
bw.write("
<
h1>
Demo file created from within a JDemo demonstration program<
/h1>
"
);
bw.write("
<
/body>
<
/html>
"
);
bw.close();
show(file);
}
/*
*
Demo showing textual output.*
/
public void demoShowText() {
show("
Hello World"
);
}
}4.6 GuiDemoCase
GuiDemoCase
is the superclass class forAwtDemoCase
andSwingDemoCase
. It only provides methods for managingWindow
objets. Those methods are required by both subclasses and by the GUI capturing code described in chapter 7.![]()
4.6.1 API Description
protected void registerDemoWindow(Window window);
Registers the given window as demo window for this GuiDemoCase. Usually called by any framework method that displays a window object.
Note that all
public Window getRegisteredDemoWindow();
Returns the demo window registered with this GuiDemoCase or
null
if there is none registered.
show
...()
methods in the sublasses ofGuiDemoCase
ensure that the displayed objects are contained in a registered window. So you will not have to care for registering your component yourself.4.7 AwtDemoCase
![]()
4.7.1 API Description
protected void show(CharSequence text);
Convenience method for showing the given text in a
java.awt.TextArea
component using a fixed width font.
protected void showProportional(CharSequence text);
Convenience method for showing the given text in a
java.awt.TextArea
component using a proportional font.
protected void show(Component component);
Convenience method for showing any kind of
java.awt.Component
object.
protected void show(Component[] components, LayoutManager layout);
Convenience method for showing an array of
java.awt.Component
objects. The specified layout manager will be used to lay out the components.
protected void show(Window window);
Convenience method for showing any kind of
java.awt.Window
object. The given object will also be registred as demo window for this democase (if not being registered already). Note that the window will be packed, centered on the screen and made non-modal if being a dialog.
protected void showAsIs(Window window);
Convenience method for showing any kind of
java.awt.Window
object. The given object will also be registred as demo window for this democase (if not being registered already). Note that the window will be made non-modal if being a dialog.
protected Frame createFrame();
Convenience method for creating a new
java.awt.Frame
object that can be used for demo implementations. The frame is automatically registered as demo window and decorated with the necessary window listener, icon, title, etc.
protected void setFrameTitle(String title);
Sets the title for the frame being created by this demo case. Setting it to
null
(default) will set the title to the name of the demo.
protected void setFrameIconImage(Image icon);
Sets the image that will be used for the frame icon when showing this demo.
4.7.2 Example Usage
In the examples directory of the JDemo distribution there is a classde.jdemo.examples.awt.AwtDemoCaseUsageDemo
containing example demos using theAwtDemoCase
API. Have a look at its commented source code in order to see proper usage of the API.4.8 SwingDemoCase
AsSwingDemoCase
is a subclass ofAwtDemoCase
you can use all of its convenience methods. In addition it provides Swing specific methods.![]()
4.8.1 API Description
protected void show(CharSequence text);
Convenience method for showing the given text in a
javax.swing.JTextPane
component using a fixed width font.
protected void showProportional(CharSequence text);
Convenience method for showing the given text in a
javax.swing.JTextPane
component using a proportional font.
protected void show(JComponent component);
Convenience method for showing any kind of
javax.swing.JComponent
object.
protected void show(Icon icon);
Convenience method for showing a
javax.swing.Icon
object.
protected void show(Icon[] icons, LayoutManager layout);
Convenience method for showing an array of
javax.swing.Icon
objects. The specified layout manager will be used to lay out the icons.
protected void show(Image image);
Convenience method for showing a
java.awt.Image
object.
protected void show(Image[] images, LayoutManager layout);
Convenience method for showing an array of
java.awt.Image
objects. The specified layout manager will be used to lay out the images.
protected void show(JPopupMenu popupMenu);
Convenience method for showing a popup menu. The menu will be "embedded" into a frame.
protected JFrame createJFrame();
Convenience method for creating a new
javax.swing.JFrame
object that can be used for demo implementations.
protected void setFrameIcon(Icon icon);
Sets the icon that will be used for the frame when showing this democase.
4.8.2 Example Usage
In the examples directory of the JDemo distribution there is a classde.jdemo.examples.jfc.SwingDemoCaseUsageDemo
containing example demos using theSwingDemoCase
API. Have a look at its commented source code in order to see proper usage of the API.4.9 LookAndFeel with SwingDemoCases
Usually setting the LookAndFeel is being done by a call to a static method in thejavax.swing.UIManager
class. However for demos this is not good practice, since we would then have to implement multiple demos of the same component in order to see it in various LookAndFeels. To avoid this problem demos are subject to the following restrictions:Setting the preferred LookAndFeel can be done by calling one of the convenience methods provided by the
- Any demo implementation can set its preferred LookAndFeel in the setup method or at the beginning of the demo method.
- Users must be able to optionally tell the Demo runner what LookAndFeel to use when running a demo. This setting superceedes the preferred LookAndFeel specified in the demo (if any).
- By default demos are run in the Java Cross Platform LookAndFeel.
SwingDemoCase
class:![]()
4.9.1 API Description
protected void setPreferredLookAndFeel(String lookAndFeelClassName);
Sets the preferred LookAndFeel to the one represented by the given LookAndFeel class name.
protected void setPreferredLookAndFeelCrossPlatform();
Sets the preferred LookAndFeel to the Java Cross Platform LookAndFeel.
protected void setPreferredLookAndFeelGtk();
Sets the preferred LookAndFeel to the Gtk LookAndFeel (
com.sun.java.swing.plaf.gtk.GTKLookAndFeel
). Note that this LookAndFeel might not be supported on some systems.
protected void setPreferredLookAndFeelMotif();
Sets the preferred LookAndFeel to the Motif LookAndFeel (
com.sun.java.swing.plaf.motif.MotifLookAndFeel
). Note that this LookAndFeel might not be supported on some systems.
protected void setPreferredLookAndFeelSystem();
Sets the preferred LookAndFeel to the system's native LookAndFeel.
Note that using a LookAndFeel not available on your system will result in a
protected void setPreferredLookAndFeelWindows();
Sets the preferred LookAndFeel to the Windows LookAndFeel (
com.sun.java.swing.plaf.windows.WindowsLookAndFeel
). Note that this LookAndFeel might not be supported on some systems.
java.lang.ClassNotFoundException
or ajava.lang.RuntimeException
causing the demo to fail when being run.4.9.2 Example Usage
In the examples directory of the JDemo distribution there is a classde.jdemo.examples.jfc.LookAndFeelDemo
containing example demos using theSwingDemoCase
LookAndFeel API. Here is an excerpt from this file containing three demos showing aJButton
object in different LookAndFeels:
Figure 4.7 shows a screenshot of the output from the example.
public class LookAndFeelDemo extends SwingDemoCase {
public void demoSystemLookAndFeel() {
setPreferredLookAndFeelSystem();
show(new JButton("
Button in system Look and Feel"
));
}
public void demoCrossPlatformLookAndFeel() {
setPreferredLookAndFeelCrossPlatform();
show(new JButton("
Button in CrossPlatform Look and Feel"
));
}
public void demoMotifLookAndFeel() {
setPreferredLookAndFeelMotif();
show(new JButton("
Button in Motif Look and Feel"
));
}
}![]()
Figure 4.7: The LookAndFeel demo example showing buttons in different LookAndFeels.
4.9.3 Comments
The default demo runner in JDemo itself uses the system LookAndFeel for its GUI. If there was no other LookAndFeel specified for the demo cases, they also would be rendered using the system LookAndFeel. In order to avoid this, JDemo initializes each Swing demo with the Java Cross Platform LookAndFeel.Since all demos are run in the same virtual machine, it can not be guaranteed that setting the LookAndFeel for one demo does not affect others. This in particular is true when the demo creates new gui components after switching the LookAndFeel, e.g. when creating a new popup window.4.10 SwtDemoCase
The most recent implementedDemoCase
subclass is the one for supporting IBM's windowing toolkit SWT. At the moment it only provides one method:![]()
4.10.1 API Description
protected Shell createShell();
Creates a new
org.eclipse.swt.widgets.Shell
object that can be used for adding widgets. The shell will automatically be made visible when returning from thedemo
...()
method. Not that calling this method more often than once during execution of a single demo will result in ade.jdemo.framework.exceptions.DemoExecutionFailedError
.
4.10.2 Example Usage
In the examples directory of the JDemo distribution there is a classde.jdemo.examples.swt.SwtDemoCaseUsageDemo
containing example demos using theSwtDemoCase
API. Here is an excerpt from this file:public class SwtDemoCaseUsageDemo extends SwtDemoCase {
Note that for executing SWT demos you must ensure that Java can access the SWT library. Usually this is done by adding the folder containing the SWT libraries to the Java library path using a command like this:
public void demoSwtLabel() {
Label label = new Label(createShell(), SWT.NONE);
label.setText("
Hello SWT World!"
);
}
public void demoExitFromWithinASwtDemoUsingAButton() {
Button button = new Button(createShell(), SWT.PUSH);
button.setText("
Exit"
);
button.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
exit();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
}-Djava.library.path=D:/java/eclipse/plugins/org.eclipse.swt.win32_3.0.0/os/win32/x86
If you want to eliminate the need for specifying the classpath andjava.library.path
options in the Java command line you can integrate the SWT JAR and DLL (for Windows) with your Java Runtime Environment (JRE) by copying the jar files to the JRE's lib/ext directory and the DLL to the JRE's bin directory (the same procedure can be applied to other platforms). Refer to the SWT documentation for more detailed information.
5.1 Launching
For launching the Demo Runner you have to run the DemoRunner classde.jdemo.swingui.DemoRunner
and specify the fully qualified name of the demo class or demo suite, that shall be loaded, as argument:Note that both thejava de.jdemo.swingui.DemoRunner org.foo.MyDemo
jdemo.jar
(orjdemo_core.jar
andjdemo_runner.jar
) and the demo class must be on theCLASSPATH
.
If you want the users to be able to browse the demo source code from within the Demo Runner you can specify a source code lookup path using the-sourcepath
or-sp
option:Similar to the Javajava de.jdemo.swingui.DemoRunner -sp src.zip org.foo.MyDemo
CLASSPATH
, thesourcepath
is a list of directories andzip
orjar
files.
For a complete description of the command line parameters of the Demo Runner use this command:java de.jdemo.swingui.DemoRunner -help
5.2 Usage
The Demo Runner mainly consists of two parts. In the upper half there is the demo tree and in the lower half there is the demo execution list:![]()
Demos can be started by double clicking them in the demo tree (of course it also works with keyboard navigation). The states of the invoked demos (see section 3.2.2) are shown in the execution list below.
Advanced features are available through the popup menu of the tree:![]()
- Run
Runs the selected demo.- Run with Look&Feel
Runs the selected Swing demo using the Look&Feel (see section 4.9) chosen from the submenu.- Copy demo identifier
Copyies the demo identifier (see section 7.1) of the selected demo to the clipboard. This is useful e.g. if you want to use the demo for automatically capturing its output (see chapter 7).- Show source code
Shows the source code of the selected demo. This item is only enabled if you have specified a source lookup path at startup (see previous section) or are using the Demo Runner from within Eclipse (see chapter 6). Figure 5.3 shows the source code displayed for the hello world demo.- Remove
Removes the selected node from the tree.- Remove duplicates
Removes demos that have the same identifier as others in the tree. This is useful e.g. when you have started the demo runner on a class folder (for example from within an IDE) containing suites and demos. JDemo will then collect both, the demos themselves and all the suites containing the demos.![]()
Figure 5.3: The source code of the Hello World demo displayed in JDemo
The demo execution list has a context menu, too:![]()
- Bring to Front
Brings the window of the selected GUI demo case to front.- Cancel
Cancels the selected demo. Only enabled if the selected demo is running.- Rerun
Reruns the selected demo.- Remove all terminated
Removes all items from the list where the demo state is finished or crashed (see section 3.2.2).
6.1 JDemo Wizards
There are three Wizards for creating demo specific stuff:
- Menu New → Other → Java → JDemo → DemoCase
Creates a new demo case class. You can specify one of the default superclasses (DemoCase
,SwingDemoCase
,AwtDemoCase
, ...).- Menu New → Other → Java → JDemo → DemoSuite
Creates a new demo suite.- Menu New → Other → Java → JDemo → Demo package
Creates a new demo package. This is just a shortcut for creating a new package named "demo".6.2 JDemo Launch Type
There is a new launch type for running demos, providing new launch menu items "Run as JDemo Demonstration" and "Debug as JDemo Demonstration".You can select a DemoCase, a DemoSuite or even a source folder containing demos to be run. The demos are being collected and shown in the Demo Runner.Selecting the context menu item "Show source code" in the Demo Runner will cause Eclipse to open the selected demo and show its source code.6.3 Misc
6.3.1 Recreate Demo Suite
New Context menu item: "Recreate Demo Suite..." for Demo Suites in the Package Explorer. Updates the selected demo suite to the DemoCase implementations in the same folder.6.3.2 Go to Referring Demos
Menu "Navigate → Go To → Referring Demos..." shows a list of all demos for the selected type or method. (This action must be enabled in "Window → Customize Perspective..." )
This chapter has not been finished and will be extended in a future version of this document.
7.1 Demo Identifier
For capturing demo output it is necessary to provide a fully qualifiedString
representation of the demo case. So each demo has a unique identifierDemoIdentifier
consisting of the fully qualified demo class name and the demo method name, separated by a colon. The Hello World demo from section 1.8 for example has the identifierde.jdemo.examples.HelloWorldDemo:demoHelloWorld
.7.2 Capturing Textual Output
Capturing the text output from aDemoCase
class is the most simple option for capturing demo output. The classde.jdemo.capture.text.TextDemoCapture
provides a simple API for this purpose:
There are two static methods for capturing the output of the demo having the given demo id or the instantiated
public static void captureText(
DemoIdentifier demoId,
Writer writer) throws Throwable;
public static void captureText(
DemoCase demoCase,
Writer writer) throws Throwable;DemoCase
object. The text output will be written to the specifiedWriter
object.7.3 Capturing File Output
A file created as demo output from within aDemoCase
class can be copied to a specified file using the classde.jdemo.capture.file.FileDemoCapture
:
Again there are two static methods for capturing the file of the demo having the given demo id or the instantiated
public static void captureFile(
DemoIdentifier id,
File outputFile) throws Throwable {
public static void captureFile(
DemoCase demoCase,
File outputFile) throws Throwable {
DemoCase
object. The file will be copied to the specifiedFile
object.7.4 Making Screenshots
Much more interesting than capturing textual output is to take screenshots from GUI demo cases. The classde.jdemo.capture.gui.GuiDemoCapture
provides an API that can be used with AWT and Swing DemoCases:
The
package de.jdemo.capture.gui;
public class GuiDemoCapture {
public BufferedImage capture(
DemoIdentifier demoId,
boolean includeFrameTitle)
throws DemoScreenCaptureException, DemoClassNotFoundException;
public void capture(
DemoIdentifier demoId,
boolean includeFrameTitle,
String format,
File file)
throws
DemoScreenCaptureException,
DemoClassNotFoundException,
IOException;
}
GuiDemoCapture
provides two methods: The first one just creates and returns aBufferedImage
object containing the screenshot. The second one also writes out the image to the specified file using the given image format. Again you need the demo id to qualify the demo case to be captured. With both methods you have the option to only capture the frame contents or to also include its borders.Note that there are increased system requirements for creating screenshots. The current implementation uses thejava.awt.Robot
class from JDK 1.3 for taking the screenshot and the new Java Image I/O Framework provided by Sun since JDK 1.4. Taking screenshots is not possible on systems in headless mode. The supported file formats depend on the imaging plugins being installed on your system. However I recommend to usePNG
since it should be available on any system and most probably fits the needs for screenshots from your program.JPG
is another alternative if your program outputs a true color image like a photo for example.Also don't forget to make sure that the display window from your demo is managed (see section 4.6).7.5 Ant Tasks
At the moment one of the standard tools for Java software deployment is Jakarta Ant. As capturing demo output is something that can be very valuable for deployment, JDemo also contains wrapper classes, making capturing available as Ant tasks.7.5.1 Capturing Text Output
The following snippet of an Ant build target defines the new Ant task demoTextCapture and uses it for capturing the output from the Hello World demo:
Running the Ant script should result in a file
<
taskdef name="
demoTextCapture"
classname="
de.jdemo.capture.anttasks.TextDemoCaptureTask"
classpath="
jdemo.jar"
/>
<
demoTextCapture
demoId="
de.jdemo.examples.HelloWorldDemo:demoHelloWorld"
outputFile="
captured_
text.txt"
>
<
classpath path="
."
/>
<
/demoTextCapture>
captured_text.txt
being created and containing the text "Hello World" as the output from that demo.The Ant task has two properties, described in table 7.1.
Parameter description required demoId
Id of the demo to capture the output from yes outputFile
File to write the result to yes
Table 7.1: Properties for the text capture Ant task
7.5.2 Capturing File Output
Capturing a file shown as demo output is just as simple as capturing text. Here is an example Ant code:
Running the Ant script should result in a file
<
taskdef name="
demoFileCapture"
classname="
de.jdemo.capture.anttasks.FileDemoCaptureTask"
classpath="
jdemo.jar"
/>
<
demoFileCapture
demoId="
de.jdemo.examples.FileLauncherDemo:demoShowHtmlFile"
outputFile="
captured_
file.html"
>
<
classpath path="
."
/>
<
/demoFileCapture>
captured_file.html
being created and containing the text html content from the demo.The Ant task has two properties, described in table 7.2.
Parameter description required demoId
Id of the demo to capture the output from yes outputFile
File to write the result to yes
Table 7.2: Properties for the filecapture Ant task
7.5.3 Making Screenshots
There is another Ant task available for making screenshots:
Running this Ant script will result in a file
<
taskdef name="
demoGuiCapture"
classname="
de.jdemo.capture.anttasks.GuiDemoCaptureTask"
classpath="
..."
/>
<
demoGuiCapture
demoId="
de.jdemo.examples.dice.demo.MyDiceDemo:demoShowRandomDice"
imageFormat="
png"
outputFile="
captured_
gui.png"
/>
dice6.png
containing the screenshot from a die as shown in figure 1.2 (b). The various properties for this Ant task are described in table 7.3.
Parameter description required demoId
Id of the demo to capture the output from yes outputFile
File to write the result image to yes imageFormat
The name of the image output format as
defined by the installed imaging library
(e.g.PNG
,JPG
)no, defaults to
the extension of
the output fileincludeTitle
Flag indicating whether the title of the
output window shall be included in the
screenshot or not (true
orfalse
)no, default is true
lookAndFeelClassName
The name of the look&feel class to be used no
Table 7.3: Properties for the screenshot Ant task
When capturing Swing demos you can specify the look and feel that shall be used by providing thelookAndFeelClassName
parameter. Table 7.4 shows the class names for popular look and feels. For more information about look and feels with demos refer to section 4.9.
Name class name notes Metal javax.swing.plaf.metal.MetalLookAndFeel
Java CrossPlatform CDE/Motif
com.sun.java.swing.plaf.motif.MotifLookAndFeel
can be used on
any platformWindows
com.sun.java.swing.plaf.windows.WindowsLookAndFeel
only available on
Microsoft Windows
systemsGTK+ com.sun.java.swing.plaf.gtk.GTKLookAndFeel
since JDK1.4.2 Mac com.sun.java.swing.plaf.mac.MacLookAndFeel
Table 7.4: Popular look&feels
7.5.4 Known limitations
Taking screenshots is a non trivial job, so there are some things you have to take care of:
- If the demo code starts threads of its own influencing the GUI, screenshots taken by JDemo might not be complete. Make sure that such code is rather processed on the event dispatch thread. For example consider using
javax.swing.SwingUtilities.invokeLater(Runnable)
.- If the demo shows an animation the result of the screencapture is indeterministic. If the animation takes a lot of CPU time the capture might fail with a timeout, since there is a quiet period on the event dispatch thread required.
- Don't open or move other windows on your desktop while screencapture takes place. Screencapture really takes screenshots and it will grabb whatever window covers the actual demo.
7.6 Image processings
Some screenshots require image processings before the images fit the requirements for the web or for other documents. As an experimental feature the JDemo project contains a few Ant tasks for such kind of image processings. Since they actually work independent of JDemo, it is likely that I will move those tasks to a separate project soon.7.6.1 Generic image processings
There is a generic Ant taskImageProcessingTask
that can be used for applying a sequence of processings to an image. At present, scaling is the only processing implemented. Here is an example that reads the filescreenshot.png
, scales the image to a width of 200 pixels using a smooth scaling algorithm and writes the resulting image to the filescreenshot_small.png
:
Table 7.5 describes the parameters of the
<
taskdef name="
imageProcessing"
classname="
de.jave.image.ant.ImageProcessingTask"
classpath="
${classpath}"
/>
<
imageProcessing
srcFile="
screenshot.png"
outputFile="
screenshot_
small.png"
>
<
rescale width="
200"
qualityHint="
smooth"
/>
<
/imageProcessing>
ImageProcessingTask
and table 7.6 describes the parameters of its nested elementrescale
.
Parameter description required srcFile
File to read the original image from yes outputFile
File to write the result image to yes imageFormat
The name of the image output format as
defined by the installed imaging library
(e.g.PNG
,JPG
)no, defaults to
the extension of
the output file
Table 7.5: Parameters for the image processing Ant task
Parameter description required width
The width of the result in pixels or as percentage
of the original image.
(e.g.800
,75%
)Exactly one of width
orheight
must be
specified.height
The height of the result in pixels or as percentage
of the original image.
(e.g.800
,75%
)Exactly one of width
orheight
must be
specified.qualityHint
Rescale filter as defined by the java.awt.Image
class. Valid values are:Smooth
,AreaAveraging
,
Default
,Replicate
andFast
no, default is Smooth
Table 7.6: Parameters for the nested rescale processing
7.6.2 Composing images
TheImageCompositionTask
loads images from multiple files and arrages them to a new image. The size of the result image is the maximum extent of all positioned images. This task was used to create figure 4.7, which is a composition of four images captured using JDemo. Here is the source code from the Ant build script:
Table 7.7 describes the parameters of the
<
taskdef name="
imageComposition"
classname="
de.jave.image.ant.ImageCompositionTask"
classpath="
${classpath}"
/>
<
imageComposition
backgroundColor="
FFFFFF"
outputFile="
${screenshot.dir}/lookandfeelbuttons.png"
>
<
image file="
${tmp.dir}/laf_
jdemo.png"
x="
0"
y="
0"
/>
<
image file="
${tmp.dir}/laf_
system.png"
x="
296"
y="
26"
/>
<
image file="
${tmp.dir}/laf_
crossplatform.png"
x="
269"
y="
95"
/>
<
image file="
${tmp.dir}/laf_
motif.png"
x="
296"
y="
169"
/>
<
/imageComposition>
ImageCompositionTask
and table 7.8 describes the parameters of its nested elementimage
.
Parameter description required outputFile
File to write the result image to yes imageFormat
The name of the image output format as
defined by the installed imaging library
(e.g.PNG
,JPG
)no, defaults to
the extension of
the output filebackgroundColor
The background color of the image to be created
as six-digit hexadecimal rgb valueNo, default is FFFFFF
Table 7.7: Parameters for the image composition Ant task
Parameter description required file
File to read the original image from yes x
The x position to add the image at no, default is 0
y
The y position to add the image at no, default is 0
Table 7.8: Parameters for the nested image element
Note that this Ant task could also be used for adding mouse cursors or other transparent images to decorate screenshots.
8.1 Automated conversion from demos to tests
The classde.jdemo.junit.Demo2TestConverter
creates a JUnit testcase (or testsuite) from the given democase (or demosuite):
public static Test createTest(IDemo demo);
The created unit test runs the demo and cancels it immediately. It fails if there is a
java.lang.Throwable
thrown during this procedure. It also stops with a timeout error if returning from the demo method takes very long. You can either use the default timeout value (30000ms in the current implementation of the framework) or specify the number of milliseconds when creating the test:
public static Test createTest(IDemo demo, long timeOutMillis);
By using the methods above you can easily add demos to your suite of unit tests. You only have to add a single line of code to your main test suite:
public class AllTests {
This code converts all demos contained in the main demo suite
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(Demo2TestConverter.createTest(AllDemos.suite()));
//add other test suites...
return suite;
}
}
AllDemos
to tests and adds them to the suite of tests.8.2 Peculiarities with demo-tests
There is one peculiarity when executing tests based on demos that show a file using theshow(File)
method in theDemoCase
class: The file is not being shown in an external browser but instead it is only being checked whether the file exists. If it does not exist, the test fails.8.3 Evaluation
Tests created from demos are nothing more than smoke tests. They only fail when something goes terribly wrong but by no means guarantee that the demo does what it should.However on the other hand those demo-tests are for free, and by ensuring that all demos can be executed, they will help you to prevent some of the most embarrassing kind of bugs in demo code. So all in all I think its worth using them.
9.1 JDemo Annotation
The JDemo annotation is defined as follows:
The annotation contains two optional elements:
package de.jdemo.annotation;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface JDemo {
public String description() default"
"
;
public String[] categories() default {};
}
- A description text in HTML format, that may describe the details of the demo. The description for a demo can then be accessed from the Demo Runner application and be presented to the user.
- An array of strings in order to assign the demo to certain categories. Categories may be used by demo runner applications e.g. for filtering demos.
9.2 Example
Here is a simple example using the JDemo annotation feature:
The example adds a HTML description to the demo method and assigns it to the categories
@JDemo(
description ="
<
h1>
Hello World<
/h1>
<
p>
Prints "Hello World!".<
/p>
"
,
categories = {"
example"
,"
public"
}
)
public void demoHelloWorld() {
show("
Hello World!"
);
}
example
andpublic
. Note that there are no predefined categories in the framework.The JDemo Demo Runner can be configured to show descriptions from annotations in an additional panel on the right (Use the View menu to adjust this setting):![]()
10.1 JDemo CVS
The source code of the complete JDemo framework is contained in the download package. You can also access the most current version from the SourceForge CVS (http://sourceforge.net/projects/jdemo/). There you will have to check out the following projects:
Project Contents JDemo The core project for the framework JDemo_build Build script for compilation and deployment JDemo_swingrunner The Swing based demo runner application JDemo_examples The examples JDemo_thirdparty Thirdparty libraries required for JDemo and deployment JDemo_tiger JDK 1.5 (Tiger) related classes e.g. for Annotations JDemo_imageprocessing Image processing code for screen capture and Ant tasks JDemo_eclipse
Eclipse plugin for Eclipse 3.0/3.1
(there also is a branch for the 2.1 version)
The JDemo_eclipse and JDemo_examples projects are optional. In order to build JDemo you can use the Ant build script from the JDemo_build project. For a full build you will need both a JDK1.4 and a JDK1.5 compiler. You must specify the paths to your compilers by creating a properties filesystem_dependent_build.properties
. There is a template for this file in the build project.10.2 Writing your own DemoRunner
Unless you have a very brillant idea for a new demo runner, I recommend contributing to the existing one. However if you want to write your own runner you are welcome to do so, too. Look at the source code of the original demo runner to get an idea of how to build the tree etc. Some utility methods for instantiating a demo can be found in the classde.jdemo.framework.util.DemoUtilities
. Once you have an instancemyDemo
of a JDemo demo you can launch using code somewhat like this:
IDemoCaseRunnable runnable = myDemo.createRunnable();
runner.addDemoStateChangeListener(new IDemoStateChangeListener() {
public void demoStateChanged(IDemoStateChangeEvent event) {
//Do whatever appropriate for the state change happened
}
});
new Thread(runnable).start();
10.3 Integrating the DemoRunner into other Applications
At the moment Eclipse is the only IDE supporting JDemo by a plugin (see chapter 6). Supporting other development environments should not be hard to be done. The wizards for creating demo cases and suites can be implemented similar as the existing ones for JUnit support. Launching demos should be done by launching the existing Runner. Feel free to ask me if you have any questions about this.
11.1 Batch Capture
An additional Ant task for capturing complete suites instead of single demos (see chapter 7) would be nice. Also optionally a Html page should be created, containing the captured images (or links to captured files).11.2 Executing Sequences of Demos
JDemo demos are unit demos: one demo case can only demonstrate a single unit - either a dialog or an exported file, for example, but not both together. In some situations I would like to be able to connect multiple demos to a more complex scenario.
Example: Given we have two demos, one that displays a dialog for entering information, and a second one for demonstrating some kind of file export. The file export works with some demonstration data, but would also work with the information that has been entered in the first demo. In this situation I would like to be able to (optionally) connect both demos, so that the user can enter the data in the dialog and also sees the exported file afterwards.
I do not yet have any idea about how to make this work. On the other hand I am also not really sure if I want to allow such complex kind of interaction. The power of JDemo is its simplicity and I cannot imagine a simple solution here. However any kind of ideas or comments are welcome.
Converted from PDFLaTeX to HTML 2005-01-08 using PDFLaTeX2Html 1.0 |
|