Question

Without creating another class that I can inject. Is it possible to mock javax.mail.Transport so I can do some mock testing of the Transport.send() method on Java EE 7?

Was it helpful?

Solution

Following up on Bill Shanon's solution since Dumbster does not have a currently working Maven Central artifact, I used GreenMail.

Then I used the following code:

final GreenMail mailServer = new GreenMail();
mailServer.start();

final Properties mailSessionProperties = new Properties();
mailSessionProperties.put("mail.smtp.port", String.valueOf(mailServer.getSmtp().getPort()));

final javax.mail.Session mailSession = javax.mail.Session.getInstance(mailSessionProperties);

testObject.setMailSession(mailSession);

That way testObject does not need to change even if it has a static call to Transport.send(message).

OTHER TIPS

If what you want is to not call Transport.send while testing then you could use this:

@RunWith(PowerMockRunner.class)
@PrepareForTest(javax.mail.Transport.class)
public class MyClassTest {
    @Before
    public void before() throws Exception {
        suppress(method(Transport.class, "send", Message.class));
    }
}

see also https://groups.google.com/forum/#!topic/powermock/r26PLsrcxyA

Another approach that hasn't been discussed is to wrap calls to Transport.send(message) in a class that delegates the call. It's a bit of overhead in your code base, but it allows you to mock your delegating class and create the outcomes you want.

public class TransportDelegator {
    public void send(Message msg) throws MessagingException {
        Transport.send(msg)
    }
}

Then mock TransportDelegator as you would in whatever framework you are using.

Yes. On way is to use Mockito. https://code.google.com/p/mockito/

public class CategoryDAOTest {

    private Transport transport = Mockito.mock(Transport.class);

    @Test
    public void sendMessage() throws MessagingException {
        transport.sendMessage(null, null);
    }
}

Or, using annotations to create the mock:

@RunWith(MockitoJUnitRunner.class)
public class CategoryDAOTest {

    @Mock
    private Transport transport;

    @Test
    public void sendMessage() throws MessagingException {
        transport.sendMessage(null, null);
    }
}  

I created a new wrapper class and Mocked it with Mockito. This prevented me from adding PowerMock to my project.

public class MyTransport{
  public void send(MineMessage msg) throws MessagingException{
    javax.mail.Transport.send(msg);
  }
}

In side test class we just need

@Mock
private MyTransport myTransport

This will do nothing when is called. You may also want to verifiy myTransport is getting called.

Mockito.verify(myTransport).send(correctMsg);

Another approach is to use a fake SMTP server such as Dumbster. The JUnit tests in the JavaMail source workspace use a similar approach.

You can try JavaMail Mock2 https://github.com/salyh/javamail-mock2

It primarily focused on IMAP/POP3 but SMTP Mock is also available. In your case the "Fullmock" mode is a good choice. Its also available in maven central.

If you are on linux / osx you can use python to create a mock smtp server, like that:

python -m smtpd -n -c DebuggingServer localhost:1025

Then it is enough if you connect to port 1025 on localhost and you can send emails. The Python code can be started by simple ProcessBuilder call (How to run Unix shell script from Java code?).

This is How I did after hours of research, I was sending a list of attachments paths along with email to my method. everything workd fine

@Test
public void testWhenMigrationReportSentSuccessfully() throws Exception {
    mockStatic(Transport.class);
    PowerMockito.doNothing().when(Transport.class, "send", any(Message.class));
    service.report(anyList(), "client@dummy.com");
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top