It can be inconvenient to unit test a class which uses Javamail (needs
SMTP server, hard to verify email contents).
It is possible however to replace the standard mail Transport with a
mock implementation.
First you need two files in META-INF which make sure the mock gets used;
in a Maven project, src/test/resources would be a good place for these.
The file
javamail.providers gives the transport class to use for the smtp protocol:
# set the javamail default provider to a mock implementation for SMTP only.
#
protocol=smtp; type=transport; class=com.myCompany.MockTransport; vendor=Acme Corporation;
In addition, the file javamail.address.map maps address types to the transport to use, its contents are:
rfc822=smtp
Finally, you need a mock Transport subclass which overrides the connect() methods and adds an implementation for sendMessage(). This example stores the last message sent in a static member; this makes it possible to retrieve the message afterwards in a unit test by using MockTransport.getLastMessage().
package com.myCompany;
import javax.mail.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Mock implementation of {@link Transport} for unit testing. This needs property file overrides
* in a META-INF on the classpath in order to work; this is in src/test/resources .
* See http://sujitpal.blogspot.com/2006/12/mock-objects-for-javamail-unit-tests.html for more information.
* This implementation stores the last message sent and adds a getter for retrieval and verification.
* @author bartas
*/
public class MockTransport extends Transport {
private static final Logger logger = LoggerFactory.getLogger(MockTransport.class);
private static Message lastMessage;
public MockTransport(Session session, URLName urlName) {
super(session, urlName);
logger.warn("constructed MockTransport instance - javamail is mocked");
}
/**
* Stores the message to send in this instance.
* @see javax.mail.Transport#sendMessage(javax.mail.Message, javax.mail.Address[])
*/
@Override
public void sendMessage(Message arg0, Address[] arg1)
throws MessagingException {
String subject = arg0.getSubject();
StringBuffer addresses = new StringBuffer("[");
for (int i=0; i<arg1.length; i++) {
addresses.append(arg1[i]);
if (i<arg1.length-1) addresses.append(",");
}
addresses.append("]");
logger.debug("sendMessage(\"{}\",{})", subject, addresses.toString());
lastMessage = arg0;
}
@Override
public void connect() throws MessagingException {
logger.debug("connect()");
}
@Override
public void connect(String arg0, int arg1, String arg2, String arg3)
throws MessagingException {
logger.debug("connect({},{},{},{})", new Object[] {arg0,arg1,arg2,arg3});
}
@Override
public void connect(String arg0, String arg1, String arg2)
throws MessagingException {
logger.debug("connect({},{},{})", new Object[] {arg0,arg1,arg2});
}
@Override
public void connect(String arg0, String arg1) throws MessagingException {
logger.debug("connect({},{})", arg0,arg1);
}
@Override
public synchronized void close() throws MessagingException {
logger.debug("close()");
}
public static Message getLastMessage() {
return lastMessage;
}
}