Dumbster Diving

December 28, 2004

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.

Read more posts in the blog archive »