Reputation: 2492
I want to test my services in spring which should send emails.
I try to use org.subethamail:subethasmtp
.
To acieve my goal I created service MySender
where I send email:
@Autowired
private MailSender mailSender;
//...
SimpleMailMessage message = new SimpleMailMessage();
message.setTo("[email protected]");
message.setSubject("Subject");
message.setText("Text");
mailSender.send(message);
// ...
To test this piece of code I created test application.properties
(in test scope):
spring.mail.host=127.0.0.1
spring.mail.port=${random.int[4000,6000]}
And test configuration class which should start Wiser SMTP server and make it reusable in tests:
@Configuration
public class TestConfiguration {
@Autowired
private Wiser wiser;
@Value("${spring.mail.host}")
String smtpHost;
@Value("${spring.mail.port}")
int smtpPort;
@Bean
public Wiser provideWiser() {
// provide wiser for verification in tests
Wiser wiser = new Wiser();
return wiser;
}
@PostConstruct
public void initializeMailServer() {
// start server
wiser.setHostname(smtpHost);
wiser.setPort(smtpPort);
wiser.start();
}
@PreDestroy
public void shutdownMailServer() {
// stop server
wiser.stop();
}
}
Expected result is that application sends email using Wiser smtp server and verify number of sended messages.
But when I run service application throws MailSendException(Couldn't connect to host, port: 127.0.0.1, 4688; timeout -1;)
.
But when I add breakpoint and try connect using telnet smtp server allow to connect and don't throw Connection refused
.
Do you have any idea why I can't test sending mails?
Full code preview is available on github: https://github.com/karolrynio/demo-mail
Upvotes: 2
Views: 5847
Reputation: 324
I faced same problem. If using some constant port number for spring.mail.port
in test Spring configuration combined with Maven tests forking, it resulted in tests randomly failing on port conflict when starting Wiser.
As noted here in comments, using random.int doesn't help - it returns different value each time it's referenced, and it's expected behavior (see this issue).
Hence, we need a different way to initialize spring.mail.port
with a random value, so it would be constant within the test execution. Here's a way to do it (thanks for advice here):
First, we may not set spring.mail.port
in test properties file at all. We'll initialize it in TestPropertySource
. We'll need a class like this:
public class RandomPortInitailizer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
int randomPort = SocketUtils.findAvailableTcpPort();
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,
"spring.mail.port=" + randomPort);
}
}
Now we can run our tests this way (not too different from what's found in OP):
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = RandomPortInitailizer.class)
public class WhenEmailingSomeStuff {
@Value("${spring.mail.host}")
String smtpHost;
@Value("${spring.mail.port}")
int smtpPort;
@Before
public void startEmailServer() {
wiser = new Wiser();
wiser.setPort(smtpPort);
wiser.setHostname(smtpHost);
wiser.start();
}
@After
public void stopEmailServer() {
wiser.stop();
}
@Test
public void testYourJavaMailSenderHere() {
//
}
}
Upvotes: 1
Reputation: 2491
in the application properties can you also add
mail.smtp.auth=false
mail.smtp.starttls.enable=false
The change your code to have these extra two values
@Value("${mail.smtp.auth}")
private boolean auth;
@Value("${mail.smtp.starttls.enable}")
private boolean starttls;
and put these options in your initializeMailServer
Properties mailProperties = new Properties();
mailProperties.put("mail.smtp.auth", auth);
mailProperties.put("mail.smtp.starttls.enable", starttls);
wiser.setJavaMailProperties(mailProperties);
wiser.setHostname(smtpHost);
wiser.setPort(smtpPort);
wiser.start();
let me know if this worked for you
Upvotes: 0