Как издеваться над javax.mail.Session - PullRequest
10 голосов
/ 21 ноября 2011

мне нужно смоделировать объект javax.mail.Session в моих модульных тестах.Класс javax.mail.Session помечен как финальный, поэтому Mockito не может создать макет.У кого-нибудь есть идеи, как это исправить?

Редактировать: Мой тест является тестом Arquillian и уже имеет аннотацию @RunWith (Arquillian.class).Поэтому powermock не вариант.

Ответы [ 9 ]

10 голосов
/ 21 ноября 2011

Вы можете немного изменить свой код. В книге «Работа с устаревшим кодом» Мартина Фаулера он описывает метод отделения внешнего API (например, Java Mail API) от кода вашего собственного приложения. Техника называется «Обертывание и кожа» и довольно проста.

Что вам нужно сделать, это просто:

  1. Создайте интерфейс MySession (который является вашим собственным материалом), извлекая методы из класса javax.mail.Session.
  2. Реализуйте этот интерфейс, создав конкретный класс (немного похожий на оригинальный javax.mail.Session)
  3. В каждом методе DELEGATE вызывается эквивалентный метод javax.mail.Session
  4. Создайте свой ложный класс, который реализует MySession: -)
  5. Обновите производственный код, чтобы использовать MySession вместо javax.mail.Session

Счастливого тестирования!

РЕДАКТИРОВАТЬ: Также посмотрите на это сообщение в блоге: http://www.mhaller.de/archives/18-How-to-mock-a-thirdparty-final-class.html

6 голосов
/ 21 ноября 2011

Используйте PowerMockito , чтобы издеваться над ним.

@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");
  }
}
5 голосов
/ 21 ноября 2011

Вы можете использовать проект Mock JavaMail .Я сначала нашел это от Kohsuke Kawaguchi .Алан Францони также имеет в своем блоге учебник для начинающих .

Когда вы помещаете этот jar-файл в путь к классам, он заменяет любую отправку почты в почтовые ящики в памяти, которую можно проверить немедленно.Это супер просто в использовании.

Добавление этого в ваш classpath, по общему признанию, является довольно жестким способом насмешки над чем-то, но вы все равно редко хотите отправлять реальные электронные письма в ваших автоматизированных тестах.

1 голос
/ 28 марта 2015

Используйте функции Java 8!

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] = "foo@foo.com";
    addresses[1] = "boo@boo.com";
    String from = "baz@baz.com";
    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("foo@foo.com"));
    verify(message).addRecipient(Message.RecipientType.TO, new InternetAddress("boo@boo.com"));
    verify(message).addFrom(new InternetAddress[]{new InternetAddress("baz@baz.com")});
    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));
};
1 голос
/ 21 ноября 2011

Если вы хотите смоделировать финальные классы, вы можете использовать нефинализатор JDave, который можно найти здесь: http://jdave.org/documentation.html#mocking

Он использует CGLib для динамического изменения байт-кода при загрузке JVM для преобразования класса вне финальный класс.

Затем эту библиотеку можно использовать с JMock2 (http://www.jmock.org/mocking-classes.html) для выполнения ваших тестов, потому что, насколько я знаю, Mockito не совместим с JDave.

0 голосов
/ 02 мая 2013

Я использую библиотеку mock-javamail .Он просто заменяет исходную реализацию javamail в classpath.Вы можете отправлять почту в обычном режиме, она просто отправляет в почтовый ящик в памяти, а не в реальный почтовый ящик.

Наконец, вы можете использовать объект MailBox для подтверждения всего, что вы хотите проверить.

0 голосов
/ 11 июля 2012

Это довольно старый вопрос, но вы всегда можете реализовать свой собственный транспорт, используя JavaMail API . С вашим собственным транспортом вы можете просто настроить его в соответствии с этой документацией . Одним из преимуществ этого подхода является то, что вы можете делать с сообщениями все, что захотите. Возможно, вы бы сохранили их в хэше / наборе, которые затем могли бы гарантировать, что они действительно были отправлены в ваших модульных тестах. Таким образом, вам не нужно издеваться над конечным объектом, вы просто реализуете свой собственный.

0 голосов
/ 24 ноября 2011

Если вы можете представить Spring в своем проекте, вы можете использовать JavaMailSender и смоделировать это. Я не знаю, насколько сложны ваши требования.

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));
}
0 голосов
/ 21 ноября 2011

См. Документы PowerMock для , работающие под JUnit 3 , так как у него не было бегунов, или используйте инструмент для манипулирования байт-кодом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...