Unit Testing Made Easy: Design Principles to Facilitate Testing
Using ClassLoaders to Support Better Design, Security, and Hot Swapping of Components
Using java.awt.Robot to Measure Performance, Capacity, and Reliability
Extreme GUI Testing: A Guide to Using the Project "JFCUnit" and HTTPUnit Extensions
Recommendations for Conference Attendees
I'm in the cafeteria watching this session on video simulcast. For you, the reader,
this means you won't get any notes until I finish eating my muffin. ...(minutes pass)... Now
I'm on my second muffin. There's some code on the screen. If you've seen Java code before it
looks very similar to that code. Squint. Yes, it is Java code.
OK, my muffins are down now so let's begin.
This is supposed to be a great article on testing JDBC code:
http://www.mockobjects.com/papers/jdbc_testfirst.html
For multi-threaded code the speaker recommends using Doug Lea's concurrency utilities.
See my notes from Doug Lea's talk earlier in the week. "If you have multi-threaded code just
start with Doug Lea's libraries to begin with."
For testing GUIs first make sure you break up your code into MVC. "A class should do one
thing an do it well." Seems like I've heard that somewhere before.
This is supposed to be a great paper on unit testing your GUIs:
http://users.vnet.wwake/xp/xp0001/index.shtml
Be careful with singletons, specifically with who calls getInstance(). Have limited
places where singletons are created and pass them into constructors for your objects.
Then your unit tests can replace or subclass the singletons if they need to.
This article discusses the issues of singletons in much more detail:
http://www-106.ibm.com/developerworks/webservices/library/co-single.html
Mock Objects are separate inner classes just for testing. You can set them up to throw
exceptions on certain method calls to give you better coverage on your unit tests. They can
provide canned data so that your unit tests can run in isolation from your database Check out
this URL for more information:
http://www.mockobjects.com
(Note to self: Find a lot of good Java articles on the web, steal their ideas, throw together
a few slides, and present at JavaOne.)
"Surface of a class has cutouts that fit interfaces or common data classes." I think this
dude had too much sugar in his coffee this morning. Next, he started talking about exposing his
composition. The rest isn't really fit to print in this high-quality publication.
Of course, XP says to write all your unit tests first:
http://www.extremeprogramming.org
The speaker also promotes thinking of the unit tests as part of the documentation.
"Write good unit tests and your design will improve."
Most of the components that I've seen could use a lot of hot swappin'. Better design is
often useful too. Once again, this session is in one of the largest rooms and it's completely
packed. A lot of people, included myself, are sitting on the floor. However, I'm one of the
upper-class floor people having a wall to lean back against, a clear view of the one of the
big screens, and finally a plug-in for my laptop. Life is good.
The speaker is Ian Griffiths, CEO of Yellow-B (just when you thought all the bad company
names were taken), and head of the Java Methodology department.
Class loaders are responsible for loading classes. Class loaders can be structured as trees.
Each class loader delegates requests to its parent before trying to satisfy it. This is called
the "parents-get-satisfied-first methodology". Class loaders read classes from the file system,
the network, or generate byte code on the fly.
Class Loaders were introduced with JDK 1.1 but like everything in JDK 1.1 they were
difficult to use. JDK 1.2 introduced features which made them simple to program. The JDK 1.4
release introduced something-another to make exceptions easier with class loaders but I missed
what he said it was.
Enough filler. Here's some code:
ClassLoader classLoaderA = new MylassLoader();
Class classB = classLoaderA.loadClass("B");
MyInterface b = (MyInterface)classB.newInstance();
b.doSomething();
There are three class loaders that ship with Java 2: java.net.URLClassLoader
(light-blue on the slide) inherits from java.security.SecureClassLoader
(orange on the slide) which intern inherits from java.lang.ClassLoader (red on the slide).
You can roll your own class loader by copying this code:
class DecryptingClassLoader extends ClassLoader
{
String key;
DecryptingClassLoader(String key)
{
this.key = key;
}
public Class findClass(String name)
{
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name)
{
// load the class data and decrypt it
...
}
}
The speaker followed with showing an XML file from his company where they map class
loaders to stuff. I couldn't tell if the "stuff" were individual class names, jar files,
or "actions" of some sort.
Now we get to the hot swappin' of classes. His explanation was very brain dead. For
class D you first get rid of all instances of class D. This is at runtime. Once that's
done the existing class loader for class D will be garbage collected next Wednesday morning.
Then you can have a different class loader that reloads a class. This was exemplified with the
stupidest, crappiest demo of all demos at this year's conference.
URLClassLoader loads classes and resources from a search path of URLs referring to
both JAR files and directories. It's useful, so remember it.
JDK 1.4 as introduced assertions and your can change their default behavior in your
class loader :
void setDefaultAssertionStatus(...)
void setPackageAssertionStatus(String pakageName,
boolean enabled)
void setClassAssertionStatus(String className,
boolean enabled)
public void clearAssertionStatus()
JSR-121 is for Application Isolation. This is for creating a subprocess within the same JVM.
Before the talk as people are still coming into the room the speaker has a demo running on
the big screens showing a very decent looking Swing GUI going through automated testing. Fields
are plugged, records are accessed, and things flash on the screen in Commander Data speed-daemon
fashion. The speaker seems like a real developer from a company that does real work. In fact,
he is. This should be a cool talk.
He's from Automatic Data Processing (ADP) in Atlanta. ADP started their development of their
middle tier server in 1997 before commercial Application Servers were available. They wrote their
own. Their system has to scale from a laptop sales demo to a processing center.
The Robot class was added to J2SE in 1.3. It's an easy-to-use class that generates native
mouse and keystroke events. The speaker's company wrapped it to use simple "testing scripts"
implemented as Java classes. TestRobot is part of their framework and wraps java.awt.Robot
to provide extra features that facilitate writing load generators.
They have a Swing client that talks HTTP with compressed serialized objects (their own brew)
to the server which then talks JDBC to their database. Their business logic is some type of 4GL
language that's stored as metadata. No more specifics were given.
The speaker switches from his slides back over to his robot that is still running. Their
application is a Human Resources Management System. Their dialogs are built at runtime using
metadata. In one course-grain call they bring back the metadata to describe a panel and the
data for the panel. Next the speaker demonstrates the keyboard navigation for his application
which besides being good for usability makes it much easier to write Robot scripts.
The application has a Robot menu (of course normal users don't see this) for choosing and
configuring tests. One of the dialogs available from it configures the number of repetitions,
the number of rows to access, etc. This is their Read/Write robot that puts a load on the server
by doing reads and updates constantly on database rows.
The next robot is the Client Load. You can set the number of repetitions, the number of
panels to display, and the number of tabs to tab-in on each panel.
They have another applet which is a Server Management Console. It displays the number of
calls to the server, the number of rolling, average, and maximum response times, and much
more. You can click on one of this dialog's rows to see similar time breakdowns for each
panel (or GUI screen). A lot of other stuff is also displayed.
Their TestRobot class is a singleton. It can't run on the system's EventQueue thread and
still fire off all the Swing events that it needs to, so it inherits from the Thread class.
A static function called execute(…) on TestRobot is passed a TestRobot.RunInterface. The run()
method on TestRobot is called to actually run the test case. TestRobot.RunInterface has two
methods:
boolean runDialog(TestRobot);
void runTest();
The RobotRW class, for the Read/Write test, implements RunInterface.
The TestRobot thread can produce events very quickly. It can't produce the next event
until the EventQueue is ready for it. Robot.setAutoWaitForIdle() is called to wait before
issuing another robot instruction. It's implemented using SwingUtilities.invokeAndWait(Runnable).
The TestRobot framework will provide the time that a test took. The speaker's company
runs repeated trials at first so that they build up their caches at the Swing client, the app
server, and the database levels. It also takes awhile for the JIT to kick it. After everything
levels off you can do a fair test.
For serializing objects over sockets they use OutputStream -> FilterOutputStream
(deflater) -> ObjectOutputStream. java.util.zip.Deflater is used for deflation.
The speaker showed some very cool graphs showing the results of running their robot tests
on different server configurations, different JVMs, etc. Running under 1.3.1 -classic is 2.5
times slower than 1.3.1 -server for their application. There's not much different running
between 1.4 -server and 1.4 -client.
They use their tests to determine how big their server should be and to benchmark a server
configuration. They measure RPCs per minute and average response time.
These URLs tell more about tuning for Hot Spot:
They ran their robot tests with different heap size settings on the JVM using these:
A. JVM defaults
B. -Xmx192m and -XX:MaxNewSize=64m
C. -Xmx128m and -XX:MaxNewSize=(missed this number)
The MaxNewSize parameter sets the portion of the heap size for new, small objects.
They have started an automated test on Friday night long enough to run all weekend with
500,000 server calls. As a result of this stress testing, they have had systems running for
months without needing maintenance.
This was a very good talk and highly informative. The speaker had real experience and
knew what he was talking about. Demoing his company's real application instead of a
dumbed-down demo was a major plus. The author's system is not open source, and in the
Q&A session he said he might look into that, get permission, etc. Someone in the audience
mentioned something about an open-source project named "Gemmy" (I think that's it anyway).
I went to the microphone and told the speaker that it seemed like he had to invent his own
JUnit-type framework on top of java.awt.Robot, and did he agree with my comparison? He didn't
understand my question, thinking the subject was still on "Gemmy" (or whatever) which he didn't
know anything about. After lunch, I noticed that my next scheduled session was on JFCUnit.
The speaker started with a decent introduction to JUnit which I won't bother repeating
here. There are several decent tutorials on the web which would be much better for you to
read instead. (Go to http://www.junit.org) JUnit is great for testing Java classes but it
can't test web pages.
HTTPUnit extends JUnit to allow automatic testing of Web sites. It emulates a web browser,
including form submission, basic HTTP authentication, cookies, milk, and automatic page
redirection. It provides methods to examine returned pages as text, and XML DOM, or
containers of forms, tables, and links. HTTPUnit parses HTML using a program called
Tidy brought to you by the makers of Tidy-Bowl.
Note that HTTPUnit can't create tests that use JavaScript. In other words, it will not
run any of your JavaScript code, so you might as well go ahead and delete it.
The classes WebConversation, WebRequest, and WebResponse are used to retrieve web pages.
The pages can be examined by:
- Parsing the input stream from the WebResponse
- Viewing the page as a DOM object
- Viewing the page as a list of WebForms, WebLinks, etc.
Here is some code:
public void testWelcomePage() throws Exception
{
WebConversation convs = new WebConversation();
WebRequest request = new GetMethodWebRequest
("http://localhost:9090/httpUnitDemo");
WebResponse resp = resp.getResponse(request);
WebForm form = response.getForms()[0];
Request = form.getRequest();
Request.setParameter( "username", "Tom" );
...
response = convers.getResponse( request );
...
WebTable flightTable = response.getTables()[0];
TableCell tcell= flightTable.getCell(0,0);
...
WebLink link = response.getLinks()[0];
...
JFCUnit extends the JUnit test suite for Swing applications. JFCUnit provides the
JFCTestHelper class that allows test methods to find components of a Swing application.
JFCUnit provides a way to manage the awtThread so test methods do not interfere with event
processing. It's presently in Beta release.
JFCTestHelper provides the following methods:
findButton(String, Container, int);
findJLabel(String, Container, int);
findNamedComponent(String, ontainer, int);
findNamedComponent(String, Class, Container, int);
findComponent(Class, Container, int);
findComponent(ComponentFinder Container, int);
JFCUnit provides two methods to manage the AWT Thread. awtSleep() and
awtSleep(long sleepTime ). The first defaults to 100ms. These don't force the AWT
thread to sleep; rather, they make your test case sleep until Swing is done doing its stuff.
Yet again, here's some more code:
public class JFCUnitDemoTester extends JFCTestCase
{
private JFCTestHelper helper;
private static Boolean winCreated = false;
private Window appWindow;
private JTabbedPane tabbedPane;
public JFCUnitDemoTester(String name)
{
super(name);
helper = new JFCTestHelper();
if( !winCreated )
{
String[] stringArray = new String[1];
JFCUnitDemo.main(stringArray);
...
See his slides for more code examples.
The speaker ran a Swing GUI and demoed using JFCUnit to test it, but it wasn't nearly
as awesome as the previous speaker's demo (using his own framework) because he used a very
naïve sample GUI to demo with. A real application for the demo would have been much more
effective.
Well, that was all the content for this session. Try browsing these sites if you really
want to learn something:
I've attended
many software development conferences over the past few years, so I thought
I'd list some suggestions based on my experience. These are for conferences in general and are
not specific to JavaOne.
Picking good speakers is a crap shoot. In my experience the best talks are given by real
developers with real experience. Consultants give you a decent chance at learning something
because they generally do real work (well most of the time), but be wary of those (consultants
and otherwise) who write too many books or who have titles like Chief Software Evangelist and
Chief Methodologist. Managers also sometimes give talks and you want to avoid them like the
plague. Talks given by engineers from big companies like Sun, IBM, and the like are fine for
finding out what APIs are coming out next, what's going to be in the next release, and similar
information that's nice to know and to research when you get back home. Just don't expect to
learn anything profound or applicable to what you do everyday. There are also a tiny minority
of speakers who are extraordinarily entertaining and who you should see no matter what their
lecture topic is. Scott Myers, Allan Cooper, and Jared Spool are good examples. They will
always teach you something even if it's the level of your own ignorance.
In light of the above, always have an exit plan. One of the best methods is to try to
always sit at the end of a seating row. If a talk is bad, go to another one or go to the
show floor and let the salespeople fall over themselves trying to interest you.
Speaking of sales people on the show floor, it's always fun to act dumb at first, listen
to their spill, then based on that ask them an extremely hard question that they're very
unlikely to have an answer for, and then walk away. The trick is to stump them good enough
to leave them starring into space long enough to allow you to grab a couple of handfuls of
vendor booty off their tables before they wake up to their sad reality of an existence.
Don't hesitate to schedule two, three, or even four classes in the same timeslot and
then makeup you mind five minutes beforehand. In the nerd lifestyle this is called
"living on the edge".
Take a laptop to type notes. Even if you're not a fast typist chances are you're
not buying yourself anything trying to scribble down notes as fast as you can on paper.
You may think you're going to type them all up when you get back home, but you're not.
If you've read an entire book on a certain topic, you generally will not get
anything out of attending a session on the same topic. Most speakers (certainly not all)
assume their audience is made up of total idiots. Even if you do get an interesting tidbit
of information out of one of these sessions it will only be after listening through thirty
minutes of material that you already know. Devote a good percentage of your classes to
topics which you know absolutely nothing about. Your expectations will be low, and you
will probably learn something.
Make a mental note of everyone else's ignorance for your own personal peace of mind.
This is a goal you can take into any conference and always be successful with. It's crystal
clear at these conferences that everyone else around you is at least as clueless as you are
and often more so. It's also interesting to watch how the industry's big-wig developers with
high notoriety generally seem to know this and often alienate themselves to corners of the
universe and do their best not to play with others. It's not hard to see why. If there's
anything you can get out of all of this, it's knowing that you are not alone in not knowing
what the answers are and, in fact, if you have the slightest idea of what the questions are
then you are already vastly ahead of everyone else.
[ Previous ]
[ Index ]