Appealing to Your Learning Style

(Tue Jan 04, 2005) [/TDD#

While teaching my Test-Driven Development with JUnit workshop, I hand out red and green pipe cleaners. One of their purposes goes with the JUnit red and green bar theme: You can hold up a green one to let me know that something I said really touched an area deep inside your brain or a red one to let me know that I need to backtrack so I don't lose you. It has proven to be a fun way to get feedback.

Another purpose of the pipe cleaners is to keep the hands of the kinesthetic learners engaged while the auditory learners are listening and the visual learners are watching. The workshop includes lots of hands-on exercises (it's a workshop) so that everyone learns by doing, but as a kinesthetic learner I know how important it is to fidget with something during the lecture parts of training. Indeed, although it may appear that they're not paying attention, making shapes out of pipe cleaners actually heightens the concentration of kinesthetic learners.

Just before the holidays, I had an opportunity to teach TDD to a great group of folks at Lands' End. When the last question had been answered at the end of two days, Ann had brought many of our names to life in red and green. The final touch was a Christmas tree and candy canes. She had also completed all of the hands-on exercises, usually before anybody else. It became a running joke that Ann couldn't sit still without those pipe cleaners, and I suspect she wouldn't have learned as much either.

Workshoppers

Listening To The Tests

(Tue Dec 28, 2004) [/TDD#

Ron Jeffries, in his online article (err... upcoming book) Adventures in C#: Using NUnit, sums things up oh so nicely in this statement about test-driven development:

It occurs to me as I write this that in the course of this book, you will probably encounter examples of doing things in ways that seem almost obtusely simple. I assure you that I'm not doing it to make the book suitable for third-graders, nor because I myself am also simple. I work that way because in the half-dozen years I've been doing Extreme Programming, I've been working in simpler and simpler ways, and my work seems to be getting better and better. So, please, when you see something here that looks odd, give it a try. Often I think you'll find it interesting.

I've been seriously practicing test-driven development for over a year now. It hasn't all been in an XP setting, nor does it need to be. Indeed, I think TDD and continous integration bring a lot to the party on their own. Unfortunately, I'm afraid all too often the baby is being thrown out with the bath water.

When I'm letting tests guide my way, I almost always find something interesting that wouldn't have been illuminated had I just slapped down the code that first popped into my brain. At first it felt awkward and a bit silly: Write a failing test, write just enough code that makes it pass, then refactor in the safety of that test. Writing just enough code is sometimes the silly part as I try to tease out the simplest solution. For some reason it's always tempting to speculate and in the process over-engineer. Yet with TDD I'm usually amazed at how little code it actually takes to build something of value.

In keeping with the TDD rhythm, I'm actually cranking out more code than without testing. And I know it's always working the way I intended it should. And the designs tend to be more responsive to change than when I was coding only after dreaming up a pattern-compliant design.

I had to rewire my brain by listening to the tests. I'm sure glad I did.

Get The Testing Bug

(Tue Dec 28, 2004) [/TDD#

Did you make a New Year's resolution to start writing more tests and enjoy better designs as a result of writing tests first? How's that going so far? If you're having a difficult time getting started or making that resolution stick, don't despair. This stuff takes practice.

To help you get started, my "A Dozen Ways to Get the Testing Bug in the New Year" article is now available on java.net. It gives you 12 practical ways to start (and keep) writing tests, regardless of your development process. It also explains how writing tests first results in the emergence of better designs. I hope you find it helpful and encouraging.

By the way, I love the "delicious" graphic designed for the article. Have I mentioned just how outstanding the java.net staff is to work with?

Spreading the TDD Meme

(Tue Dec 28, 2004) [/TDD#

Tim Bray weighs in on his experiences with TDD in Yet Another TDD Sermon. I have a lot of respect for Tim. He says TDD helps him write better programs. I'm obviously already drinking the TDD kool-aid. But if I weren't, why wouldn't I want to try it to see if it helps me write better programs?

I'm happy to see this story play over and over again. I gave two TDD talks in Raleigh, NC last weekend. Both were well attended and folks were enthusiastic about writing more tests on their projects. This TDD stuff is going to catch on, I tell ya.

Dumbster Diving

(Tue Dec 28, 2004) [/TDD#

I'm currently writing an automated monitoring and notification program for a client. Users of their Java-powered web application can elect to receive email when certain things of interest have changed. The notification frequency is configurable. For example, as a user of this system you might want to be notified at the end of every day if something really important happened that day. For less important stuff you can wait for an email at the end of the week.

The monitoring step involves running a hunk o' Java when a timer pops to determine if something of interest has indeed changed since the last time interval. I'm using Quartz to schedule the monitoring jobs because it's light-weight, supports cron-like schedules, is as portable as Java can be, and it passes the fits-in-one-JAR-file test. Its only downside is that it's difficult to test schedules with long intervals. I'll come back to why I want to control its internal clock in a future blog. For now, trust that I know how many places Quartz directly calls System.currentTimeMillis() and it's greater than one.

The notification step uses JavaMail because my program lives inside of a bigger Java program and, thankfully, JavaMail is one of the less onerous Java APIs. Because successfully sending email is such an important part of the process, I'd like to test that it actually works. However, I'd like to do that without spamming my email account. I'm really only interested in validating that a correctly-formatted email was outbound. I could certainly mock it at the code level to make sure I'm using the API correctly. But wouldn't it be nice to have a fake SMTP server that squirrels away emails it receives and then lets you test for their existence?

That's where Dumbster comes in. It plugs in at the network level and intercepts email sent by JavaMail (or any other mail sender). Here's the test:

import com.dumbster.smtp.SimpleSmtpServer;
import com.dumbster.smtp.SmtpMessage;
import java.util.Iterator;
import javax.mail.MessagingException;
import junit.framework.TestCase;

public class MailSenderTest extends TestCase {
    
    public void testSend() throws MessagingException {
    
        String smtpHost = "localhost";
        int smtpPort = 2525;
        
        SimpleSmtpServer server = SimpleSmtpServer.start(smtpPort);
        
        MailSender sender = new MailSender(smtpHost, smtpPort);

        String toAddress = "barney@rubble.com";        
        String fromAddress = "fred@flintstone.com";
        String subject = "Caveman Greeting";
        String body = "Yabba Dabba Doo!";
          
        sender.send(toAddress, fromAddress, subject, body);

        server.stop();

        assertEquals(1, server.getReceievedEmailSize());
        Iterator inbox = server.getReceivedEmail();
        SmtpMessage email = (SmtpMessage)inbox.next();
        assertEquals(toAddress, email.getHeaderValue("To"));
        assertEquals(fromAddress, email.getHeaderValue("From"));
        assertEquals(subject, email.getHeaderValue("Subject"));
        assertEquals(body, email.getBody());    
    }
}

Notice that it starts the SimpleSmtpServer before sending the email and stops it after the email has been sent. Then the assertions verify that the server received the expected email. That's all there is to it: simple and unintrusive. Now I can deliver this test along with the code and anybody, anywhere can run it without unknowingly sending me email every time the test passes.

Practicing What I Preach

(Tue Dec 28, 2004) [/TDD#

Jeff Brekke astutely responded to my ConfigurationTest:

I'm wondering why you chose to use the constructor instead of setUp()? I guess I've grown a habit to always use setUp() and I was just wondering what the reasoning was. I try to question my habits often. ;)

Good thing you questioned it, Jeff... because I was wrong! Oh, there's nothing fundamentally wrong with using the constructor. The initialization code need run only once to capture the original system properties. But I put that code in the constructor for all the wrong reasons. Indeed, I fell prey to a cunning programmer trap. You see, I wanted to put the initialization code in the setUp() method. It makes for nice symmetry with the tearDown() method. When I'm reading tests and see those two methods, I know just what's going on.

But just as I was going for the setUp() method, I was struck by irrational fear: "Oh no, this initialization code could be slow. I don't want it to run for every test method. That will be really slow!" So, without measuring how slow, I took the bait. That's right, I was prematurely optimizing. And it bit me.

For some reason I forgot that a new instance of the test case is created for each test method. Consequently, the test case constructor is run for every invocation of the setUp() method. That's just how JUnit works. I was assuming the constructor was only run once, and that putting the seemingly slow code in the constructor would save time. I was wrong. Not only did it not save time, but it also compromised the readability of my test.

Here's the really bad (read: embarrassing) part: I've been aggressively preaching the perils of premature optimization. Indeed, my name is on the chapter in Bitter EJB that warns of performance tuning antipatterns. And the very first antipattern in that chapter is, you guessed it... Premature Optimization!

Shame on me. Perhaps by publicly falling on my sword I'll remember next time to focus on code clarity first, then measure for performance, if it matters. Thanks for keeping me on the rails, Jeff.

Evangelizing Test-Driven Development

(Tue Dec 28, 2004) [/TDD#

I had a great turnout for my "Test-Driven Development With JUnit" talk this weekend at the No Fluff, Just Stuff symposium in sunny Seattle, despite going up against Glenn's stacked deck at the same time. ;-)

It's always rewarding to get stellar reviews on a talk, but this time I got a few extra goodies. A number of attendees used the word "convincing" on their evaluation form. Now it's not unusual that folks give TDD a whirl after listening to me extol its virtues. After all, with all those green bars flashing by you can't help but want to pop one yourself. But this is the first time I've received nearly-unanimous reports that the talk was convincing.

So on the plane ride home when I was sifting through the evals, I started thinking about what was different this time. I'm always looking for opportunities to use feedback as a resource. The results of every talk I give get piped into the next talk. And I've given this talk about a dozen times, so it's been... err... mercilessly refactored.

Earlier in the week I had taught a course on TDD using JUnit to a bright team of QA and development folks. Their enthusiasm no doubt kept me wired through the weekend. I'm very much looking forward to watching JUnit and TDD take root on their project. Perhaps that enjoyable experience got me started on the right foot.

But in general I'm just really passionate about TDD. When I'm up there talking, I'm not shy about telling you how insecure and unproductive I am without it. I guess I've never been too shy about sharing my failures. What do I have to hide? Indeed, the more I hide the less I learn. Example: Oh sure, I used to write unit tests after my code seemed to be working, but I loathed doing it and my tests weren't all that good. I was always hurriedly testing in hopes of getting back to the creative process of writing code. (Maybe I'm a bad programmer, methinks.) Only now have I discovered that writing tests first is part of the creativity. Better yet, I'm writing better tests because I'm actually enjoying the design benefits and the freedom the tests afford me to change code with impunity.

And I've been studying and practicing object-oriented design and patterns for over a decade now. I've got all the books and t-shirts to prove it. But when I'm honest with myself I know that most of that time I was really frustrated. Too often my beautiful UML designs turned ugly when I tried to codify them. (Maybe I'm a bad designer, methinks.) It's a bit hard to swallow, but I think I've learned more about OO in the last two years since picking up TDD than I did in all the years previous. But more importantly, I'm having fun with it because my designs are actually working. They're simpler, yet they still exhibit the qualities we associate with a good design: high cohesion and low coupling.

So here's my advice if you're trying to convince your team to use TDD: Just honestly tell them how it's working for you. And then stop talking. Don't worry about trying to convince them that TDD should also work for them. Yeah, I know that the books say it should and x number of programmers can't be wrong, but forget all that. Our industry is already polluted with tools and techniques that were supposed to work. Folks have to decide for themselves to try TDD and then shape it into their own technique -- based on their context. You can't do that for them, and they'll hate you all the more if you try. And if listening to a so-called "OO expert" talk about his frailties helps, I'd love an opportunity to tell them, and show them, how TDD is working for me.

How Do I Test That? : Properties

(Tue Dec 28, 2004) [/TDD#

Today I'm crafting an app that's configurable through properties. (No, not XML, just plain 'ol properties. Silly me.) I want to write a test that, when it passes, gives me confidence that system-level properties (e.g. -Dkey=value) override properties specified programmatically. How do I test that?

Well, I could fire up the test from the command line, once with a system property set and once without, but that's messy. And my tests are control freaks. They don't like relying on external input.

The solution I settled on is fairly pedestrian. In fact, I'm betting you already have an answer in mind. But since I've written a similar test more than once over the last couple years, I figured it might be worth posting.

Keep in mind, there's no guarantee as to the order in which the test methods will be run. Thus, each test method wants its own "sandbox". So, not only are my tests control freaks, they're also sharing-challenged. Here goes:

public class ConfigurationTest extends TestCase {

    private Properties originalProperties;
    
    public ConfigurationTest() {
        originalProperties = new Properties();
        originalProperties.putAll(System.getProperties());
    }
    
    public void tearDown() {
        System.setProperties(originalProperties);
    }

    public void testSetProperty() {
        String key = "key";
        String value = "setValue";
        
        Properties properties = new Properties();
        properties.setProperty(key, value);
        
        Configuration config = new Configuration(properties);
        assertEquals(value, config.getProperty(key));
    }

    public void testSystemPropertyOverridesSetProperty() {
        String key = "key";
        
        Properties properties = new Properties();
        properties.setProperty(key, "setValue");
        
        System.setProperty(key, "systemValue");
        
        Configuration config = new Configuration(properties);
        assertEquals("systemValue", config.getProperty(key));
    }
}

That's a lot of code for a little bit of testing, you say? Well, it does appear to be a disproportionate amount of code, but I generally err on the verbose side and then wait until enough pressure builds to force a refactoring. I just can't see a good refactoring from here that enhances readability. Perhaps you will. In the meantime, I can continue running these tests at no cost.

I enjoyed writing this test (yet again) because it reminded me of the value of testability hooks. In this case, I can bypass the command-line interface completely and set system-level properties once the system is running. I'm learning that if I write my code driven by tests, then odds are those hooks emerge naturally. That is, my tests uncover new methods based on need rather than speculation. And sometimes those methods turn out to be quite handy outside the context of a text.

Stumped trying to write a test? Let me know. We'll both learn!