При создании приложения Spring Boot может возникнуть необходимость добавить конфигурацию почты. На самом деле, настройка почты в Spring Boot не сильно отличается от настройки в Spring Bootless приложении. Но как проверить, что конфигурация и отправка почты работают нормально? Давайте посмотрим.
Я предполагаю, что у нас есть простое загрузочное приложение Spring Boot. Если нет, то самый простой способ сделать это — использовать Spring Initializr .
Добавление зависимости javax.mail
Начнем с добавления зависимости javax.mail в build.gradle : compile 'javax.mail:mail:1.4.1' . Нам также потребуется Spring Context Support (если она отсутствует), которая содержит класс поддержки JavaMailSender . Зависимость: compile("org.springframework:spring-context-support")
Конфигурация на основе Java
Spring Boot поддерживает конфигурацию на основе Java. Чтобы добавить конфигурацию почты, мы добавляем класс @Configuration аннотацией @Configuration . Свойства хранятся в mail.properties (но это не обязательно). Значения свойств могут быть введены непосредственно в bean-компоненты с @Value аннотации @Value :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
@Configuration@PropertySource("classpath:mail.properties")public class MailConfiguration { @Value("${mail.protocol}") private String protocol; @Value("${mail.host}") private String host; @Value("${mail.port}") private int port; @Value("${mail.smtp.auth}") private boolean auth; @Value("${mail.smtp.starttls.enable}") private boolean starttls; @Value("${mail.from}") private String from; @Value("${mail.username}") private String username; @Value("${mail.password}") private String password; @Bean public JavaMailSender javaMailSender() { JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); Properties mailProperties = new Properties(); mailProperties.put("mail.smtp.auth", auth); mailProperties.put("mail.smtp.starttls.enable", starttls); mailSender.setJavaMailProperties(mailProperties); mailSender.setHost(host); mailSender.setPort(port); mailSender.setProtocol(protocol); mailSender.setUsername(username); mailSender.setPassword(password); return mailSender; }} |
Аннотация @PropertySource делает mail.properties доступным для внедрения с помощью @Value . аннотаций. Если это не сделано, вы можете ожидать исключения: java.lang.IllegalArgumentException: Could not resolve placeholder '<name>' in string value "${<name>}" .
И mail.properties :
|
1
2
3
4
5
6
7
8
|
mail.protocol=smtpmail.host=localhostmail.port=25mail.smtp.auth=falsemail.smtp.starttls.enable=falsemail.from=me@localhostmail.username=mail.password= |
Конечная точка почты
Чтобы иметь возможность отправить электронное письмо в нашем приложении, мы можем создать конечную точку REST. Мы можем использовать SimpleMailMessage в Spring для быстрой реализации этой конечной точки. Давайте посмотрим:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
@RestControllerclass MailSubmissionController { private final JavaMailSender javaMailSender; @Autowired MailSubmissionController(JavaMailSender javaMailSender) { this.javaMailSender = javaMailSender; } @RequestMapping("/mail") @ResponseStatus(HttpStatus.CREATED) SimpleMailMessage send() { SimpleMailMessage mailMessage = new SimpleMailMessage(); mailMessage.setTo("someone@localhost"); mailMessage.setReplyTo("someone@localhost"); mailMessage.setFrom("someone@localhost"); mailMessage.setSubject("Lorem ipsum"); mailMessage.setText("Lorem ipsum dolor sit amet [...]"); javaMailSender.send(mailMessage); return mailMessage; }} |
Запуск приложения
Теперь мы готовы запустить приложение. Если вы используете CLI, введите: gradle bootRun , откройте браузер и перейдите к localhost:8080/mail . На самом деле вы должны увидеть ошибку, которая говорит о том, что соединение с почтовым сервером не удалось. Как и ожидалось.
Поддельный SMTP-сервер
FakeSMTP — это бесплатный Fake SMTP-сервер с графическим интерфейсом, написанный на Java, для тестирования электронной почты в приложениях. Мы будем использовать его для проверки работоспособности представления. Пожалуйста, скачайте приложение и просто запустите его, java -jar fakeSMTP-<version>.jar : java -jar fakeSMTP-<version>.jar . После запуска поддельного SMTP-сервера, запустите сервер.
Теперь вы можете снова вызвать конечную точку REST и увидеть результат в Fake SMTP!
Но под тестированием я не имел в виду ручное тестирование! Приложение все еще полезно, но мы хотим автоматически проверить почтовый код.
Модульное тестирование почтового кода
Чтобы иметь возможность автоматически проверять отправку почты, мы будем использовать Wiser — инфраструктуру / утилиту для модульного тестирования почты на основе SubEtha SMTP . Простой низкоуровневый API-интерфейс SubEthaSMTP подходит для написания практически любых приложений для получения почты.
Использование Wiser очень просто. Во-первых, нам нужно добавить тестовую зависимость в build.gradle : testCompile("org.subethamail:subethasmtp:3.1.7") . Во-вторых, мы создаем интеграционный тест с JUnit, Spring и Wiser:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = Application.class)@WebAppConfigurationpublic class MailSubmissionControllerTest { private Wiser wiser; @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setUp() throws Exception { wiser = new Wiser(); wiser.start(); mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); } @After public void tearDown() throws Exception { wiser.stop(); } @Test public void send() throws Exception { // act mockMvc.perform(get("/mail")) .andExpect(status().isCreated()); // assert assertReceivedMessage(wiser) .from("someone@localhosts") .to("someone@localhost") .withSubject("Lorem ipsum") .withContent("Lorem ipsum dolor sit amet [...]"); }} |
SMTP-сервер инициализируется, запускается в методе @Before и останавливается в методе @Teardown . После отправки сообщения утверждение сделано. Утверждение должно быть создано, поскольку структура не предоставляет никакого. Как вы заметите, нам нужно работать с объектом Wiser, который предоставляет список полученных сообщений:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
public class WiserAssertions { private final List<WiserMessage> messages; public static WiserAssertions assertReceivedMessage(Wiser wiser) { return new WiserAssertions(wiser.getMessages()); } private WiserAssertions(List<WiserMessage> messages) { this.messages = messages; } public WiserAssertions from(String from) { findFirstOrElseThrow(m -> m.getEnvelopeSender().equals(from), assertionError("No message from [{0}] found!", from)); return this; } public WiserAssertions to(String to) { findFirstOrElseThrow(m -> m.getEnvelopeReceiver().equals(to), assertionError("No message to [{0}] found!", to)); return this; } public WiserAssertions withSubject(String subject) { Predicate<WiserMessage> predicate = m -> subject.equals(unchecked(getMimeMessage(m)::getSubject)); findFirstOrElseThrow(predicate, assertionError("No message with subject [{0}] found!", subject)); return this; } public WiserAssertions withContent(String content) { findFirstOrElseThrow(m -> { ThrowingSupplier<String> contentAsString = () -> ((String) getMimeMessage(m).getContent()).trim(); return content.equals(unchecked(contentAsString)); }, assertionError("No message with content [{0}] found!", content)); return this; } private void findFirstOrElseThrow(Predicate<WiserMessage> predicate, Supplier<AssertionError> exceptionSupplier) { messages.stream().filter(predicate) .findFirst().orElseThrow(exceptionSupplier); } private MimeMessage getMimeMessage(WiserMessage wiserMessage) { return unchecked(wiserMessage::getMimeMessage); } private static Supplier<AssertionError> assertionError(String errorMessage, String... args) { return () -> new AssertionError(MessageFormat.format(errorMessage, args)); } public static <T> T unchecked(ThrowingSupplier<T> supplier) { try { return supplier.get(); } catch (Throwable e) { throw new RuntimeException(e); } } interface ThrowingSupplier<T> { T get() throws Throwable; }} |
Резюме
Всего за пару строк кода мы смогли автоматически протестировать почтовый код. Пример, представленный в этой статье, не сложен, но показывает, как легко начать работу с SubEtha SMTP и Wiser.
Как вы проверяете свой почтовый код?
| Ссылка: | Тестирование почтового кода в приложении Spring Boot от нашего партнера по JCG Рафаля Боровца в блоге Codeleak.pl . |
