I have been working on a project for quite long time. I had written quite a lot of integration tests(39). All of the tests used to pass. Recently I decided to add spring actuator starter project. But after adding spring actuator some of my integration tests are failing. These test are used to test the java mail sender. I am using green mail to actually test java mail sender. Since then I had realized I won’t be needing actuator so I ran a “git restore .” to go back to my previous commit. But the tests still don’t work. I have no idea what is going wrong here. When I run the tests I get most of the times assertion failed, green mail should receive 1 mail but it never does. But sometimes I also get this exception
Failed messages: jakarta.mail.MessagingException: can’t determine local email address
But this error is not consistent, most of the times I get assertion failed.
Please Note I am using @Async to send to the mail asynchronously. I have added the EmailService and the EmailServiceTest. Also note I have an AbstractBaseIntegrationTest class which actually spins up a 2 test containers (MySql and redis) along with the green mail server to test the mails.
AbstractBaseIntegrationTest class:
package com.sadi.pinklifeline.integrationtests;
import com.icegreen.greenmail.configuration.GreenMailConfiguration;
import com.icegreen.greenmail.junit5.GreenMailExtension;
import com.icegreen.greenmail.util.ServerSetupTest;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;
public abstract class AbstractBaseIntegrationTest {
protected static final MySQLContainer MYSQL_CONTAINER;
protected static final GenericContainer<?> REDIS_CONTAINER;
@RegisterExtension
protected static GreenMailExtension greenMail = new GreenMailExtension(ServerSetupTest.SMTP)
.withConfiguration(GreenMailConfiguration.aConfig().withUser("pinklifeline", "pinklifeline"))
.withPerMethodLifecycle(false);
static {
MYSQL_CONTAINER = new MySQLContainer(DockerImageName.parse("mysql:latest"))
.withDatabaseName("pinklifeline")
.withUsername("pinklifeline")
.withPassword("pinklifeline");
REDIS_CONTAINER = new GenericContainer<>(DockerImageName.parse("redis/redis-stack:latest"))
.withExposedPorts(6379, 8001);
REDIS_CONTAINER.start();
MYSQL_CONTAINER.start();
}
@DynamicPropertySource
public static void dynamicProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", MYSQL_CONTAINER::getJdbcUrl);
registry.add("spring.datasource.password", MYSQL_CONTAINER::getPassword);
registry.add("spring.datasource.username", MYSQL_CONTAINER::getUsername);
registry.add("spring.data.redis.host", REDIS_CONTAINER::getHost);
registry.add("spring.data.redis.port", REDIS_CONTAINER::getFirstMappedPort);
}
}
EmailService:
package com.sadi.pinklifeline.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class EmailService{
private final JavaMailSender mailSender;
private final Logger logger = LoggerFactory.getLogger(EmailService.class);
public EmailService(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
@Async
public void sendSimpleEmail(String to, String subject, String text) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(to);
message.setSubject(subject);
message.setText(text);
mailSender.send(message);
logger.debug("Email sent to {}", to);
}
}
EmailServiceTest:
package com.sadi.pinklifeline.integrationtests;
import com.icegreen.greenmail.util.GreenMailUtil;
import com.sadi.pinklifeline.service.UserRegistrationAndVerificationService;
import jakarta.mail.internet.MimeMessage;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
public class EmailServiceTest extends AbstractBaseIntegrationTest {
@Autowired
private UserRegistrationAndVerificationService userRegVerService;
@Value("${verification.email.message}")
private String verificationEmailMessage;
@Value("${verification.email.timeout}")
private int optExpiration;
@Test
public void sendSimpleEmailTest() throws InterruptedException {
int minutes = optExpiration / 60;
String otp = "1234";
String message = String.format(verificationEmailMessage, otp, minutes);
userRegVerService.sendVerificationEmail("[email protected]", otp);
Thread.sleep(2000); // This is necessary because sendSimpleEmail event is async
MimeMessage[] messages = greenMail.getReceivedMessages();
Assertions.assertThat(messages.length).isEqualTo(1);
Assertions.assertThat(GreenMailUtil.getBody(messages[0])).isEqualTo(message);
}
}
This is the config class that enables Async
@Configuration
@EnableAsync
public class SpringAsyncConfig {
}
I am using intellij Idea ultimate to run this code with Java Sdk 21.My project is 99% done. I just want it work like it had been for months. I had no issues with the tests specially with greenMail and java mail sender.
I tried removing spring boot actuator tests still fail. I tried removing my local maven repository and install all the packages again but it still doesn’t work. I removed @Async and ran the tests, this the tests work.
I tried running the tests in a GITHUB workflow runner. Surprisingly all the tests pass in the runner but not in my local machine. If anybody has any insight into my problem, I will be highly grateful for your advice.
3