【问题标题】:Test sending email in Spring在 Spring 中测试发送电子邮件
【发布时间】:2016-07-05 19:28:50
【问题描述】:

我想在春季测试我应该发送电子邮件的服务。 我尝试使用org.subethamail:subethasmtp

为了实现我的目标,我创建了服务MySender 我发送电子邮件:

@Autowired
private MailSender mailSender;

//...
    SimpleMailMessage message = new SimpleMailMessage();
    message.setTo("example@example.com");
    message.setSubject("Subject");
    message.setText("Text");
    mailSender.send(message);
// ...

为了测试这段代码,我创建了测试application.properties(在测试范围内):

spring.mail.host=127.0.0.1
spring.mail.port=${random.int[4000,6000]}

并测试配置类,它应该启动 Wiser SMTP 服务器并使其在测试中可重用:

@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();
    }

}

预期结果是应用程序使用 Wiser smtp 服务器发送电子邮件并验证已发送消息的数量。

但是当我运行服务应用程序时抛出MailSendException(Couldn't connect to host, port: 127.0.0.1, 4688; timeout -1;)。 但是当我添加断点并尝试使用 telnet smtp 服务器连接时,允许连接并且不要抛出Connection refused

你知道为什么我不能测试发送邮件吗?

完整的代码预览可在 github 上获得: https://github.com/karolrynio/demo-mail

【问题讨论】:

  • 在测试执行时,聪明的服务器还没有完成启动。在运行测试之前,您可能需要在 @Before 中执行某些操作以确保套接字处于活动状态。
  • 我不确定,因为在日志中我有信息表明服务器在测试日志之前启动,但我尝试在运行测试之前等待服务器启动。
  • 我发现了错误。我的问题的原因是配置。行:spring.mail.port=${random.int[4000,6000]},因为 spring 向 bean 注入了 2 个不同的值。 Bean MailSender 的端口值与 Wiser 不同。感谢您的帮助。

标签: spring spring-boot automated-tests integration-testing


【解决方案1】:

我遇到了同样的问题。如果在测试 Spring 配置中为 spring.mail.port 使用某个恒定端口号并结合 Maven 测试分叉,则在启动 Wiser 时会导致测试在端口冲突时随机失败。 如 cmets 中所述,使用 random.int 并没有帮助 - 每次引用它时都会返回不同的值,这是预期的行为(参见 issue)。 因此,我们需要一种不同的方法来使用随机值初始化spring.mail.port,因此它在测试执行中是恒定的。这是一种方法(感谢here的建议):

首先,我们可能根本不会在测试属性文件中设置spring.mail.port。我们将在TestPropertySource 中初始化它。我们需要这样一个类:

public class RandomPortInitailizer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        int randomPort = SocketUtils.findAvailableTcpPort();
        TestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,
                "spring.mail.port=" + randomPort);
    }
}

现在我们可以通过这种方式运行我们的测试(与 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() {
        //
    }
}

【讨论】:

    【解决方案2】:

    在应用程序属性中也可以添加

    mail.smtp.auth=false
    mail.smtp.starttls.enable=false
    

    更改您的代码以具有这两个额外的值

     @Value("${mail.smtp.auth}")
     private boolean auth;
    
     @Value("${mail.smtp.starttls.enable}")
     private boolean starttls;
    

    并将这些选项放入您的 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();
    

    如果这对你有用,请告诉我

    【讨论】:

    • 我稍后再检查。谢谢。
    • 它不起作用,但我找到了其他用于测试发送电子邮件的库,我尝试了一下。
    • 那个库是什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 2017-09-22
    • 1970-01-01
    • 2011-04-13
    • 2016-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多