English 中文(简体)
如何 mo。 邮件。 届会
原标题:How to mock a javax.mail.Session

i need to mock a javax.mail.Session object in my unit tests. The class javax.mail.Session is marked final so Mockito is not able to create a mock. Does anyone have an idea how to fix this?

Edit: My test is an Arquillian test and has already an annotation @RunWith(Arquillian.class). Therefore powermock is not an option.

问题回答

You may refactor your code a little bit. In the "Working with Legacy Code" book by Martin Fowler, he describes a technique of separating the external API (think Java Mail API) from your own application code. The technique is called "Wrap and Skin" and is pretty simple.

你应该做的是:

  1. Create an interface MySession (which is your own stuff) by extracting methods from the javax.mail.Session class.
  2. Implement that interface by creating a concrete class (looking a bit like the original javax.mail.Session)
  3. In each method DELEGATE the call to equivalent javax.mail.Session method
  4. Create your mock class which implements MySession :-)
  5. Update your production code to use MySession instead of javax.mail.Session

幸福检测!

EDIT: Also take a look at this blog post: http://www.mhaller.de/archives/18-How-to-mock-a-thirdparty-final-class.html

http://code.google.com/p/powermock/wiki/MockitoUsage13”

@RunWith(PowerMockRunner.class)
// We prepare PartialMockClass for test because it s final or we need to mock private or static methods
@PrepareForTest(javax.mail.Session.class)
public class YourTestCase {

  @Test
  public void test() throws Exception {

    PowerMockito.doReturn(value).when(classUnderTest, "methodToMock", "parameter1");
  }
}

您可使用Mock Javamail项目。 我先从。 Alan Franzoni还拥有一个primer for it

当你把这一杰尔档案放在你的班子里时,它就把任何邮件寄给记忆箱,可以立即检查。 它很容易使用。

Adding this to your classpath is admittedly a pretty heavy handed way to mock something, but you rarely want to send real emails in your automated tests anyway.

使用 Java8功能!

public class SendEmailGood {
    private final Supplier<Message> messageSupplier;
    private final Consumer<Message> messageSender;

    public SendEmailGood(Supplier<Message> messageSupplier,
                         Consumer<Message> messageSender) {
        this.messageSupplier = messageSupplier;
        this.messageSender = messageSender;
    }

    public void send(String[] addresses, String from, 
                     String subject, String body) 
                     throws MessagingException {
        Message message = messageSupplier.get();
        for (String address : addresses) {
           message.addRecipient
             (Message.RecipientType.TO, new InternetAddress(address));
        }
        message.addFrom(new InternetAddress[]{new InternetAddress(from)});
        message.setSubject(subject);
        message.setText(body);
        messageSender.accept(message);
    } 
}

之后,你的测试守则将研究如下内容:

@Test
public void sendBasicEmail() throws MessagingException {
    final boolean[] messageCalled = {false};

    Consumer<Message> consumer = message -> {
            messageCalled[0] = true;
    };

    Message message = mock(Message.class);
    Supplier<Message> supplier = () -> message;

    SendEmailGood sendEmailGood = new SendEmailGood(supplier, consumer);
    String[] addresses = new String[2];

    addresses[0] = "[email protected]";
    addresses[1] = "[email protected]";
    String from = "[email protected]";
    String subject = "Test Email";
    String body = "This is a sample email from us!";

    sendEmailGood.send(addresses, from, subject, body);
    verify(message).addRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
    verify(message).addRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
    verify(message).addFrom(new InternetAddress[]{new InternetAddress("[email protected]")});
    verify(message).setSubject(subject);
    verify(message).setText(body);

    assertThat(messageCalled[0]).isTrue();
}

创建一体化测试,展示真正的会议和运输。

Consumer<Message> consumer = message -> {
    try {
        Transport.send(message);
    } catch (MessagingException e) {
        e.printStackTrace();
    }
};

Supplier<Message> supplier = () -> {
    Properties properties = new Properties();
    return new MimeMessage(Session.getDefaultInstance(properties));
};

如果你能够将春天引入你的项目,你可以使用 Java邮件和ck。 我不知道你的要求是多么复杂。

import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;

@Test
public void createAndSendBookChangesMail() {

    // Your custom service layer object to test

    MailServiceImpl service = new MailServiceImpl();

    // MOCK BEHAVIOUR

    JavaMailSender mailSender = mock(JavaMailSender.class);
    service.setMailSender(mailSender);

    // PERFORM TEST

    service.createAndSendMyMail("some mail message content");

    // ASSERT

    verify(mailSender).send(any(SimpleMailMessage.class));
}

I use the mock-javamail library. It just replace the origin javamail implementation in the classpath. You can send mails normally, it just sends to in-memory MailBox, not a real mailbox.

Finally, you can use the MailBox object to assert anything you want to check.





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签