Earlier this week The Grinder 3.0 was released. The Grinder is a Java load testing framework, similar to something like JMeter. If you have the need for doing distributed load testing, you should give it a try and see what you think.
I had the occasion recently to evaluate the Grinder for a test system I was building. I was really pleasantly surprised by everything that I found. The Grinder has a fairly clean aesthetic that is hard to quantify but makes getting started a pleasant experience. What I found the most enjoyable about it was the use of Jython to script the actual test activity. Python has a reputation for clean, beautiful code and I found that it was actually fun to hack on the test scripts (once I refreshed my Pythonese a bit).
Because the Grinder reloads the scripts and configuration on each run, it is trivial to start up the console and your agents, then have very fast modify / run cycles as nothing needs to be restarted. You just modify the test in your editor and hit play on the console. This allows you to very rapidly whip your test into shape. Kind of reminds me of Rails…
One place where the Jython scripting really shines is the ability to use Jython to wrap a timer around a method call, something that would be far more annoying and messy in Java. To me, this feels like a great example of the use of multiple languages to best solve a problem. Here’s an example from the Script Gallery: [source:python]
# A shorter alias for the grinder.logger.output() method.
log = grinder.logger.output</p>
# Create a Test with a test number and a description. The test will be
# automatically registered with The Grinder console if you are using
# it.
test1 = Test(1, “Log method”)
# Wrap the log() method with our Test and call the result logWrapper.
# Calls to logWrapper() will be recorded and forwarded on to the real
# log() method.
logWrapper = test1.wrap(log)
# A TestRunner instance is created for each thread. It can be used to
# store thread-specific data.
class TestRunner:
# This method is called for every run.
def __call__(self):
logWrapper(“Hello World”)
[/source]
Here the log is a method and logWrapper wraps a timer around the method tied to test1 so that when logWrapper is invoked, the operation of the log method is automatically timed and saved as a transaction. In a lot of testing frameworks, the equivalent of this is a lot less elegant.
I investigated extending The Grinder to handle some unusual needs I had and the Grinder guys were quite gracious with their time. In the process I did a deep dive in their code and came away very impressed. Concepts are nicely represented, the code is clean, testing level is good. It’s clear the main developers know what they’re doing and have built a high-quality code base.
Ultimately, it turned out for me that The Grinder was lacking a couple
of things I needed, although it was more that my needs were
unusual than that the Grinder is lacking something important. I would still highly recommend it as a great framework to use. I ended up reluctantly rolling my own framework, wishing I had many of the features that the Grinder already does.