Thursday 1 March 2012

Mock Testing for Java Mail

Testing the email related code comes with its own challenges,
  • we may need a dedicated test mail server with test mail box
  • verification part of the test can not be executed right after the setup of test due to the latency in the mail delivery (due to milliseconds delay the test may fail).
  • setup and maintenance may cost its own penalties
Especially in CI and Unit testing, testing email part of the code is not so easy.

There are few good alternatives with Mock Mail testing, one of the interesting and very handy options is Mock-JavaMail. It does not require any additional setup or configuration, just drop the jar into classpath, that's all it requires. 

It redirects all the mails to in-memory mail box which can be easily used in unit tests.

Lets see this with small example. 

Maven Dependency configuration 

Include the following dependency in maven (if not using maven, just drop the jar to classpath)

               <dependency>
        <groupId>org.jvnet.mock-javamail</groupId>
  <artifactId>mock-javamail</artifactId>
  <version>1.9</version>
  <scope>test</scope>
  </dependency>

Example Mail Code

I have used Apache Commons Mail api for this example for simplicity, but works fine with any implementation of Java Mail.

package com.nutpan.example;

import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;

public class MyMailSender {

public void sendMail(String to, String from, String subject, String msg) throws EmailException {
Email email = new SimpleEmail();
email.addTo(to);
email.setFrom(from);
email.setSubject(subject);
email.setMsg(msg);
email.setHostName("testmail.com");
email.send();
}

}

JUnit Test Code

package com.nutpan.example;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;

import java.io.IOException;
import java.util.List;
import java.util.Properties;

import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;

import org.apache.commons.mail.EmailException;
import org.junit.Before;
import org.junit.Test;
import org.jvnet.mock_javamail.Mailbox;


public class MyMailSenderTest {

private MyMailSender mailSender;

@Before
public void setUp() {
mailSender = new MyMailSender();
//clear Mock JavaMail box
Mailbox.clearAll();
}

@Test
public void testSendInRegualarJavaMail() throws MessagingException, IOException, EmailException {

String subject = "Test1";
String body = "Test Message1";
mailSender.sendMail("test.dest@nutpan.com", "test.src@nutpan.com", subject, body);
Session session = Session.getDefaultInstance(new Properties());
Store store = session.getStore("pop3");
store.connect("nutpan.com", "test.dest", "password");

Folder folder = store.getFolder("inbox");

folder.open(Folder.READ_ONLY);
Message[] msg = folder.getMessages();

assertTrue(msg.length == 1);
assertEquals(subject, msg[0].getSubject());
assertEquals(body, msg[0].getContent());
folder.close(true);
store.close();
}

@Test
public void testSendInMockWay() throws MessagingException, IOException, EmailException {

String subject = "Test2";
String body = "Test Message2";
mailSender.sendMail("test.dest@nutpan.com", "test.src@nutpan.com", subject, body);
List<Message> inbox = Mailbox.get("test.dest@nutpan.com");
assertTrue(inbox.size() == 1);
assertEquals(subject, inbox.get(0).getSubject());
assertEquals(body, inbox.get(0).getContent());

}
}


First Test uses the regular Javamail approach for reading the mail and the other one uses the Mock-JavaMail  approach to read the mails from the Mock Email Server. I have included the whole import statements to show the different apis from where the classes imported (JavaMail and some from Mock-JavaMail).

You can get more information about this work at 

http://java.net/projects/mock-javamail

There are few more alternatives too, following are some of the few

Wiser
dumbster
Aspirin


give a try and keep me posted.... Better tests better software... 

4 comments:

  1. Interesting java post that I think would be well received by readers at DZone (the home of Javalobby). Please contact me if you'd be interested in having your content promoted among a community of core java devs. You can reach me at egenesky at dzone dot com.

    ReplyDelete
  2. Hey !!
    what a post u had share. Really like it. such a great work, beautifully done here. The way you are explaining it also good as well.Thanks for sharing.

    ReplyDelete
  3. Really helps , thanks.

    ReplyDelete
  4. Thanks a lot! :) This exactly explained what should I do.

    ReplyDelete