首页 > 解决方案 > 意外异常,预期但是是

问题描述

我正在尝试实现邮件服务(org.springframework.mail.javamail),功能工作得非常好,但是在使用mockito5 而不是 powermockito编写单元测试用例时,我无法涵盖 catch(MessagingException e) and catch(IOException e)

在此处输入图像描述

这是一段实现代码UsageReportBillingMailService.java

@Service
@Slf4j
public class UsageReportBillingMailService {

    @Value("${mail_receivers.mail_to:''}")
    private String[] mailToList;

    @Autowired
    private JavaMailSender emailSender;

    @Autowired
    private IUsageReportBillingRepository billingRepository;

    public void send(String period) {
        try {
            log.info("{} Getting usage billing report from DB ", UsageReportConstants.USAGE_REPORT_BILLING_MAIL_SERVICE_LOG);
            UsageReportBilling billingReportForPeriod = billingRepository.findByPeriod(period);
            if (billingReportForPeriod == null) {
                log.error("{} Cannot get the report from DB ", UsageReportConstants.USAGE_REPORT_BILLING_MAIL_SERVICE_LOG);
                throw new ReportNotFoundException(UsageReportConstants.REPORT_NOT_FOUND);
            }
            String reportHeader = UsageReportConstants.BILLING_REPORT_CSV_HEADER;
            String reportContent = billingReportForPeriod.getPeriod() + UsageReportConstants.COMMA +
                    billingReportForPeriod.getDeviceCount() + UsageReportConstants.COMMA +
                    billingReportForPeriod.getStorageUsed() + UsageReportConstants.COMMA +
                    billingReportForPeriod.getApiSuccessCount() + UsageReportConstants.COMMA +
                    billingReportForPeriod.getApiFailCount() + UsageReportConstants.COMMA +
                    billingReportForPeriod.getEventCount();

            File attachmentFile = generateAttachmentFile(UsageReportConstants.BILLING_REPORT_FILE_NAME_PREFIX + period, UsageReportConstants.CSV_FILE_EXT, reportHeader.concat("\n" + reportContent));
            prepareMail(mailToList, UsageReportConstants.MAIL_FROM, UsageReportConstants.MAIL_SUBJECT + " " + period, UsageReportConstants.MAIL_BODY + " " + period, attachmentFile);

        } catch (IOException e) {
            log.error("{} Cannot create attachment file ", UsageReportConstants.USAGE_REPORT_BILLING_MAIL_SERVICE_LOG);
        } catch (MessagingException e) {
            log.error("{} if multipart creation failed ", UsageReportConstants.USAGE_REPORT_BILLING_MAIL_SERVICE_LOG);
        }
    }

    private File generateAttachmentFile(String fileName, String fileType, String fileContent) throws IOException {
        log.info("{} Generating File from content for mail attachment ", UsageReportConstants.USAGE_REPORT_BILLING_MAIL_SERVICE_LOG);
        byte[] outputBytes = fileContent.getBytes(StandardCharsets.UTF_8);
        File tempFile = File.createTempFile(fileName, fileType, null);
        FileOutputStream fos = new FileOutputStream(tempFile);
        fos.write(outputBytes);
        return tempFile;
    }

    private void prepareMail(String[] toList, String from, String mailSubject, String mailBody, File attachment) throws MessagingException {
        log.info("{} Preparing mail and sending to listed recipient ", UsageReportConstants.USAGE_REPORT_BILLING_MAIL_SERVICE_LOG);
        MimeMessage message = emailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setSubject(mailSubject);
        helper.setText(mailBody);
        helper.setTo(toList);
        helper.setFrom(from);
        helper.addAttachment(attachment.getName(), attachment);
        emailSender.send(message);
    }
}

我试图在 Junit 测试用例中涵盖的内容UsageReportBillingMailServiceTest.java

@RunWith(SpringRunner.class)
public class UsageReportBillingMailServiceTest {

    @InjectMocks
    private UsageReportBillingMailService usageReportBillingMailService;

    @Mock
    private UsageReportBilling usageReportBilling;

    @Mock
    private JavaMailSender emailSender;

    @Mock
    private IUsageReportBillingRepository usageReportBillingRepository;

    private String period = "2020-06";

    @Test
    public void verifySendEmail() {
        MimeMessage mimeMessage = Mockito.mock(MimeMessage.class);
        ReflectionTestUtils.setField(usageReportBillingMailService, "mailToList", new String[]{"info@testmail.com", "info@testmail.com"});
        Mockito.when(usageReportBillingRepository.findByPeriod(period)).thenReturn(buildUsageReportBilling());
        Mockito.when(emailSender.createMimeMessage()).thenReturn(mimeMessage);
        usageReportBillingMailService.send(period);
        Assert.assertNull(null);
    }


    @Test(expected = ReportNotFoundException.class)
    public void verifySendEmailWhenReportNotFoundExceptionThrown() {
        MimeMessage mimeMessage = Mockito.mock(MimeMessage.class);
        Mockito.when(usageReportBillingRepository.findByPeriod("2029-01")).thenReturn(null);
        usageReportBillingMailService.send(period);
        Assert.assertNull(" ReportNotFound Exception Expected ");
    }

/*
 // this is not working
    @Test(expected = IOException.class)
    public void verifySendEmailWhenIOExceptionThrown() throws IOException {
        FileOutputStream fos = Mockito.mock(FileOutputStream.class);
        ReflectionTestUtils.setField(usageReportBillingMailService, "mailToList", new String[]{"info@testmail.com", "info@testmail.com"});
        Mockito.when(usageReportBillingRepository.findByPeriod(period)).thenReturn(buildUsageReportBilling());
        Mockito.doThrow(new IOException("this")).when(usageReportBillingMailService).send(period);
        usageReportBillingMailService.send(period);
        Assert.assertNull(" IOException Expected ");
    }

 // this is not working
    @Test(expected = MessagingException.class)
    public void verifySendEmailWhenMessagingExceptionThrown() throws MessagingException {
        MimeMessage mimeMessage = Mockito.mock(MimeMessage.class);
        ReflectionTestUtils.setField(usageReportBillingMailService, "mailToList", new String[]{"info@testmail.com", "info@testmail.com"});
        Mockito.when(usageReportBillingRepository.findByPeriod(period)).thenReturn(buildUsageReportBilling());
        Mockito.when(emailSender.createMimeMessage()).thenReturn(mimeMessage);
        Mockito.doThrow(new MessagingException("this")).when(usageReportBillingMailService).send(period);
        usageReportBillingMailService.send(period);
        Assert.assertNull(" MessagingException Expected ");
    }
*/

    private UsageReportBilling buildUsageReportBilling() {
        UsageReportBilling billingReport = new UsageReportBilling();
        billingReport.setPeriod(period);
        billingReport.setDeviceCount(100L);
        billingReport.setStorageUsed(10000L);
        billingReport.setApiSuccessCount(1000L);
        billingReport.setApiFailCount(10L);
        billingReport.setEventCount(0L);
        return billingReport;
    }
}

在此处输入图像描述

标签: spring-bootjunitmockitojakarta-mailtestcase

解决方案


MessagingExceptionMimeMessageHelper在创建对象时抛出。因此,您可以创建一个方法来创建此对象并模拟该方法调用以引发此异常。

UsageReportBillingMailService current = this;

private void prepareMail(String[] toList, String from, String mailSubject, String mailBody, File attachment) throws MessagingException {
    log.info("{} Preparing mail and sending to listed recipient ", UsageReportConstants.USAGE_REPORT_BILLING_MAIL_SERVICE_LOG);
    MimeMessage message = emailSender.createMimeMessage();
    MimeMessageHelper helper = current.createMimeMessageHelper(message, true);
    helper.setSubject(mailSubject);
    helper.setText(mailBody);
    helper.setTo(toList);
    helper.setFrom(from);
    helper.addAttachment(attachment.getName(), attachment);
    emailSender.send(message);
}

MimeMessageHelper createMimeMessageHelper(MimeMessage message, boolean multipart) {
    return new MimeMessageHelper(message, multipart);
}

在测试中

    when(mocked.createMimeMessageHelper(any(MimeMessage.class), anyBoolean())
    .thenThrow(new MessagingException("test"));
    FieldSetter.setField(usageReportBillingMailServiceInstance, UsageReportBillingMailService.class.getDeclaredField("current"), mocked);
    usageReportBillingMailServiceInstance.prepareMessage(...)

推荐阅读