Dave
Dave

Reputation: 19150

Having trouble mocking an email server using JUnit

I'm trying to mock sending an email (for the purposes of JUnit, v4.8.1, testing) and decided to use Dumbster, which I found through SO. I'm using version 1.6. I have this in my JUnit test …

    SimpleSmtpServer server = SimpleSmtpServer.start();
    boolean ret = m_emailSvc.sendEmail("[email protected]", 
                                       "[email protected]", 
                                       "localhost", 
                                       "Test", 
                                       "Test Body");
    Assert.assertTrue(ret);
    server.stop();

and I send an email this way …

public boolean sendEmail(final String toEmail,
                      final String fromEmail,
                      final String smtpHost,
                      final String subject,
                      final String body)
{

    boolean ret = true;
    // Get system properties
    Properties properties = System.getProperties();

    // Setup mail server
    properties.setProperty("mail.smtp.host", smtpHost);

    // Get the default Session object.
    Session session = Session.getDefaultInstance(properties);

    try{
       // Create a default MimeMessage object.
       MimeMessage message = new MimeMessage(session);

       // Set From: header field of the header.
       message.setFrom(new InternetAddress(fromEmail));

       // Set To: header field of the header.
       message.addRecipient(Message.RecipientType.TO,
                                new InternetAddress(toEmail));

       // Set Subject: header field
       message.setSubject(subject);

       // Now set the actual message
       message.setText(body);

       // Send message
       Transport.send(message);
    }catch (MessagingException mex) {
       ret = false;
       LOG.error(mex.getMessage(), mex);
    }   // try
    return ret;
}   // sendEmail

This fails with the exception below. Does anyone know what I'm doing wrong or is there an easier way to mock sending an email in a JUnit test?

java.net.BindException: Permission denied
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.PlainSocketImpl.socketBind(PlainSocketImpl.java:521)
    at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:414)
    at java.net.ServerSocket.bind(ServerSocket.java:326)
    at java.net.ServerSocket.<init>(ServerSocket.java:192)
    at java.net.ServerSocket.<init>(ServerSocket.java:104)
    at com.dumbster.smtp.SimpleSmtpServer.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:680)
[ERROR]: org.mainco.subco.email.service.EmailServiceImpl - Could not connect to SMTP host: localhost, port: 25
javax.mail.MessagingException: Could not connect to SMTP host: localhost, port: 25;

nested exception is: java.net.ConnectException: Connection refused at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1934) at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:638) at javax.mail.Service.connect(Service.java:295) at javax.mail.Service.connect(Service.java:176) at javax.mail.Service.connect(Service.java:125) at javax.mail.Transport.send0(Transport.java:194) at javax.mail.Transport.send(Transport.java:124) at org.mainco.subco.email.service.EmailServiceImpl.sendEmail(EmailServiceImpl.java:62) at org.mainco.subco.email.service.EmailServiceTest.testSendEmail(EmailServiceTest.java:23) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) Caused by: java.net.ConnectException: Connection refused at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:382) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:241) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:228) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:384) at java.net.Socket.connect(Socket.java:527) at java.net.Socket.connect(Socket.java:476) at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:288) at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:231) at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1900)

Upvotes: 0

Views: 2918

Answers (2)

Dave
Dave

Reputation: 19150

I decided to mock the static call from the Transport class instead, using PowerMock (v.1.5.1).

@RunWith(PowerMockRunner.class)
public class EmailServiceTest
{

@Autowired
private EmailService m_emailSvc = new EmailServiceImpl();

@Test
@PrepareForTest( Transport.class )
public final void testSendEmail()
{
    suppress(methodsDeclaredIn(Transport.class));
    boolean ret = m_emailSvc.sendEmail("[email protected]",
                                       "[email protected]", 
                                       "localhost",
                                       "Test",
                                       "Test Body");
    Assert.assertTrue(ret);
}   // testSendEmail

Upvotes: 1

John B
John B

Reputation: 32959

What about wrapping the call to Transport is a mockable object? Inject the mock and verify the call.

What I mean is something like this...

class MyTransport{
    public void send(MimeMessage message){
        Transport.send(message);
    }
}

Then inject an instance of this class into your class above. In your production env you have the same code. However, when doing testing you could pass in a Mock for MyTransport and thereby verify the call to send without the need of a server.

Upvotes: 0

Related Questions