فهرست منبع

Merge branch 'master-jdk21' of https://gitee.com/zhijiantianya/ruoyi-vue-pro

# Conflicts:
#	yudao-dependencies/pom.xml
#	yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java
#	yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java
YunaiV 1 سال پیش
والد
کامیت
6c3f88bacd

+ 5 - 1
yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java

@@ -48,7 +48,7 @@ public class SchedulerManager {
                 .withIdentity(jobHandlerName).build();
         // 创建 Trigger 对象
         Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
-        // 新增调度
+        // 新增 Job 调度
         scheduler.scheduleJob(jobDetail, trigger);
     }
 
@@ -80,6 +80,10 @@ public class SchedulerManager {
      */
     public void deleteJob(String jobHandlerName) throws SchedulerException {
         validateScheduler();
+        // 暂停 Trigger 对象
+        scheduler.pauseTrigger(new TriggerKey(jobHandlerName));
+        // 取消并删除 Job 调度
+        scheduler.unscheduleJob(new TriggerKey(jobHandlerName));
         scheduler.deleteJob(new JobKey(jobHandlerName));
     }
 

+ 2 - 0
yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java

@@ -22,6 +22,8 @@ public interface ErrorCodeConstants {
     ErrorCode JOB_CHANGE_STATUS_EQUALS = new ErrorCode(1_001_001_003, "定时任务已经处于该状态,无需修改");
     ErrorCode JOB_UPDATE_ONLY_NORMAL_STATUS = new ErrorCode(1_001_001_004, "只有开启状态的任务,才可以修改");
     ErrorCode JOB_CRON_EXPRESSION_VALID = new ErrorCode(1_001_001_005, "CRON 表达式不正确");
+    ErrorCode JOB_HANDLER_BEAN_NOT_EXISTS = new ErrorCode(1_001_001_006, "定时任务的处理器 Bean 不存在");
+    ErrorCode JOB_HANDLER_BEAN_TYPE_ERROR = new ErrorCode(1_001_001_007, "定时任务的处理器 Bean 类型不正确,未实现 JobHandler 接口");
 
     // ========== API 错误日志 1-001-002-000 ==========
     ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1_001_002_000, "API 错误日志不存在");

+ 27 - 14
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImpl.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.module.infra.service.job;
 
+import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
 import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager;
 import cn.iocoder.yudao.framework.quartz.core.util.CronUtils;
 import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobPageReqVO;
@@ -9,15 +11,12 @@ import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobSaveReqVO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO;
 import cn.iocoder.yudao.module.infra.dal.mysql.job.JobMapper;
 import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum;
+import jakarta.annotation.Resource;
 import org.quartz.SchedulerException;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
-import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.List;
-
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.containsAny;
 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
@@ -41,24 +40,25 @@ public class JobServiceImpl implements JobService {
     @Transactional(rollbackFor = Exception.class)
     public Long createJob(JobSaveReqVO createReqVO) throws SchedulerException {
         validateCronExpression(createReqVO.getCronExpression());
-        // 校验唯一性
+        // 1.1 校验唯一性
         if (jobMapper.selectByHandlerName(createReqVO.getHandlerName()) != null) {
             throw exception(JOB_HANDLER_EXISTS);
         }
-        // 插入
+        // 1.2 校验 JobHandler 是否存在
+        validateJobHandlerExists(createReqVO.getHandlerName());
+
+        // 2. 插入 JobDO
         JobDO job = BeanUtils.toBean(createReqVO, JobDO.class);
         job.setStatus(JobStatusEnum.INIT.getStatus());
         fillJobMonitorTimeoutEmpty(job);
         jobMapper.insert(job);
 
-        // 添加 Job 到 Quartz 中
+        // 3.1 添加 Job 到 Quartz 中
         schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression(),
                 createReqVO.getRetryCount(), createReqVO.getRetryInterval());
-        // 更新
+        // 3.2 更新 JobDO
         JobDO updateObj = JobDO.builder().id(job.getId()).status(JobStatusEnum.NORMAL.getStatus()).build();
         jobMapper.updateById(updateObj);
-
-        // 返回
         return job.getId();
     }
 
@@ -66,22 +66,35 @@ public class JobServiceImpl implements JobService {
     @Transactional(rollbackFor = Exception.class)
     public void updateJob(JobSaveReqVO updateReqVO) throws SchedulerException {
         validateCronExpression(updateReqVO.getCronExpression());
-        // 校验存在
+        // 1.1 校验存在
         JobDO job = validateJobExists(updateReqVO.getId());
-        // 只有开启状态,才可以修改.原因是,如果出暂停状态,修改 Quartz Job 时,会导致任务又开始执行
+        // 1.2 只有开启状态,才可以修改.原因是,如果出暂停状态,修改 Quartz Job 时,会导致任务又开始执行
         if (!job.getStatus().equals(JobStatusEnum.NORMAL.getStatus())) {
             throw exception(JOB_UPDATE_ONLY_NORMAL_STATUS);
         }
-        // 更新
+        // 1.3 校验 JobHandler 是否存在
+        validateJobHandlerExists(updateReqVO.getHandlerName());
+
+        // 2. 更新 JobDO
         JobDO updateObj = BeanUtils.toBean(updateReqVO, JobDO.class);
         fillJobMonitorTimeoutEmpty(updateObj);
         jobMapper.updateById(updateObj);
 
-        // 更新 Job 到 Quartz 中
+        // 3. 更新 Job 到 Quartz 中
         schedulerManager.updateJob(job.getHandlerName(), updateReqVO.getHandlerParam(), updateReqVO.getCronExpression(),
                 updateReqVO.getRetryCount(), updateReqVO.getRetryInterval());
     }
 
+    private void validateJobHandlerExists(String handlerName) {
+        Object handler = SpringUtil.getBean(handlerName);
+        if (handler == null) {
+            throw exception(JOB_HANDLER_BEAN_NOT_EXISTS);
+        }
+        if (!(handler instanceof JobHandler)) {
+            throw exception(JOB_HANDLER_BEAN_TYPE_ERROR);
+        }
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void updateJobStatus(Long id, Integer status) throws SchedulerException {

+ 45 - 26
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/job/JobServiceImplTest.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.infra.service.job;
 
+import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager;
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
@@ -8,7 +9,9 @@ import cn.iocoder.yudao.module.infra.controller.admin.job.vo.job.JobSaveReqVO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobDO;
 import cn.iocoder.yudao.module.infra.dal.mysql.job.JobMapper;
 import cn.iocoder.yudao.module.infra.enums.job.JobStatusEnum;
+import cn.iocoder.yudao.module.infra.job.job.JobLogCleanJob;
 import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
 import org.quartz.SchedulerException;
 import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Import;
@@ -23,6 +26,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString
 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.verify;
 
 @Import(JobServiceImpl.class)
@@ -35,6 +39,9 @@ public class JobServiceImplTest extends BaseDbUnitTest {
     @MockBean
     private SchedulerManager schedulerManager;
 
+    @MockBean
+    private JobLogCleanJob jobLogCleanJob;
+
     @Test
     public void testCreateJob_cronExpressionValid() {
         // 准备参数。Cron 表达式为 String 类型,默认随机字符串。
@@ -48,11 +55,15 @@ public class JobServiceImplTest extends BaseDbUnitTest {
     public void testCreateJob_jobHandlerExists() throws SchedulerException {
         // 准备参数 指定 Cron 表达式
         JobSaveReqVO reqVO = randomPojo(JobSaveReqVO.class, o -> o.setCronExpression("0 0/1 * * * ? *"));
-
-        // 调用
-        jobService.createJob(reqVO);
-        // 调用,并断言异常
-        assertServiceException(() -> jobService.createJob(reqVO), JOB_HANDLER_EXISTS);
+        try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+            springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(reqVO.getHandlerName())))
+                    .thenReturn(jobLogCleanJob);
+
+            // 调用
+            jobService.createJob(reqVO);
+            // 调用,并断言异常
+            assertServiceException(() -> jobService.createJob(reqVO), JOB_HANDLER_EXISTS);
+        }
     }
 
     @Test
@@ -60,18 +71,22 @@ public class JobServiceImplTest extends BaseDbUnitTest {
         // 准备参数 指定 Cron 表达式
         JobSaveReqVO reqVO = randomPojo(JobSaveReqVO.class, o -> o.setCronExpression("0 0/1 * * * ? *"))
                 .setId(null);
-
-        // 调用
-        Long jobId = jobService.createJob(reqVO);
-        // 断言
-        assertNotNull(jobId);
-        // 校验记录的属性是否正确
-        JobDO job = jobMapper.selectById(jobId);
-        assertPojoEquals(reqVO, job, "id");
-        assertEquals(JobStatusEnum.NORMAL.getStatus(), job.getStatus());
-        // 校验调用
-        verify(schedulerManager).addJob(eq(job.getId()), eq(job.getHandlerName()), eq(job.getHandlerParam()),
-                eq(job.getCronExpression()), eq(reqVO.getRetryCount()), eq(reqVO.getRetryInterval()));
+        try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+            springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(reqVO.getHandlerName())))
+                    .thenReturn(jobLogCleanJob);
+
+            // 调用
+            Long jobId = jobService.createJob(reqVO);
+            // 断言
+            assertNotNull(jobId);
+            // 校验记录的属性是否正确
+            JobDO job = jobMapper.selectById(jobId);
+            assertPojoEquals(reqVO, job, "id");
+            assertEquals(JobStatusEnum.NORMAL.getStatus(), job.getStatus());
+            // 校验调用
+            verify(schedulerManager).addJob(eq(job.getId()), eq(job.getHandlerName()), eq(job.getHandlerParam()),
+                    eq(job.getCronExpression()), eq(reqVO.getRetryCount()), eq(reqVO.getRetryInterval()));
+        }
     }
 
     @Test
@@ -109,15 +124,19 @@ public class JobServiceImplTest extends BaseDbUnitTest {
             o.setId(job.getId());
             o.setCronExpression("0 0/1 * * * ? *");
         });
-
-        // 调用
-        jobService.updateJob(updateReqVO);
-        // 校验记录的属性是否正确
-        JobDO updateJob = jobMapper.selectById(updateReqVO.getId());
-        assertPojoEquals(updateReqVO, updateJob);
-        // 校验调用
-        verify(schedulerManager).updateJob(eq(job.getHandlerName()), eq(updateReqVO.getHandlerParam()),
-                eq(updateReqVO.getCronExpression()), eq(updateReqVO.getRetryCount()), eq(updateReqVO.getRetryInterval()));
+        try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) {
+            springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(updateReqVO.getHandlerName())))
+                    .thenReturn(jobLogCleanJob);
+
+            // 调用
+            jobService.updateJob(updateReqVO);
+            // 校验记录的属性是否正确
+            JobDO updateJob = jobMapper.selectById(updateReqVO.getId());
+            assertPojoEquals(updateReqVO, updateJob);
+            // 校验调用
+            verify(schedulerManager).updateJob(eq(job.getHandlerName()), eq(updateReqVO.getHandlerParam()),
+                    eq(updateReqVO.getCronExpression()), eq(updateReqVO.getRetryCount()), eq(updateReqVO.getRetryInterval()));
+        }
     }
 
     @Test

+ 6 - 0
yudao-module-system/yudao-module-system-biz/pom.xml

@@ -127,6 +127,12 @@
             <groupId>com.xingyuv</groupId>
             <artifactId>spring-boot-starter-captcha-plus</artifactId> <!-- 验证码,一般用于登录使用 -->
         </dependency>
+
+        <dependency>
+            <groupId>org.dromara.hutool</groupId>
+            <artifactId>hutool-extra</artifactId> <!-- 邮件 -->
+        </dependency>
+
     </dependencies>
 
 </project>

+ 0 - 21
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/mail/MailAccountConvert.java

@@ -1,21 +0,0 @@
-package cn.iocoder.yudao.module.system.convert.mail;
-
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.mail.MailAccount;
-import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-@Mapper
-public interface MailAccountConvert {
-
-    MailAccountConvert INSTANCE = Mappers.getMapper(MailAccountConvert.class);
-
-    default MailAccount convert(MailAccountDO account, String nickname) {
-        String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail();
-        return new MailAccount().setFrom(from).setAuth(true)
-                .setUser(account.getUsername()).setPass(account.getPassword())
-                .setHost(account.getHost()).setPort(account.getPort()).setSslEnable(account.getSslEnable());
-    }
-
-}

+ 11 - 6
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java

@@ -1,11 +1,8 @@
 package cn.iocoder.yudao.module.system.service.mail;
 
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.extra.mail.MailAccount;
-import cn.hutool.extra.mail.MailUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
-import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
@@ -14,11 +11,12 @@ import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
 import cn.iocoder.yudao.module.system.service.member.MemberService;
 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
 import com.google.common.annotations.VisibleForTesting;
+import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.hutool.extra.mail.*;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import javax.annotation.Resource;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -105,11 +103,11 @@ public class MailSendServiceImpl implements MailSendService {
     public void doSendMail(MailSendMessage message) {
         // 1. 创建发送账号
         MailAccountDO account = validateMailAccount(message.getAccountId());
-        MailAccount mailAccount  = MailAccountConvert.INSTANCE.convert(account, message.getNickname());
+        MailAccount mailAccount  = buildMailAccount(account, message.getNickname());
         // 2. 发送邮件
         try {
             String messageId = MailUtil.send(mailAccount, message.getMail(),
-                    message.getTitle(), message.getContent(),true);
+                    message.getTitle(), message.getContent(), true);
             // 3. 更新结果(成功)
             mailLogService.updateMailSendResult(message.getLogId(), messageId, null);
         } catch (Exception e) {
@@ -118,6 +116,13 @@ public class MailSendServiceImpl implements MailSendService {
         }
     }
 
+    private MailAccount buildMailAccount(MailAccountDO account, String nickname) {
+        String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail();
+        return new MailAccount().setFrom(from).setAuth(true)
+                .setUser(account.getUsername()).setPass(account.getPassword().toCharArray())
+                .setHost(account.getHost()).setPort(account.getPort()).setSslEnable(account.getSslEnable());
+    }
+
     @VisibleForTesting
     MailTemplateDO validateMailTemplate(String templateCode) {
         // 获得邮件模板。考虑到效率,从缓存中获取

+ 14 - 17
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java

@@ -1,8 +1,6 @@
 package cn.iocoder.yudao.module.system.service.mail;
 
 import cn.hutool.core.map.MapUtil;
-import cn.hutool.extra.mail.MailAccount;
-import cn.hutool.extra.mail.MailUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
@@ -15,6 +13,7 @@ import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer;
 import cn.iocoder.yudao.module.system.service.member.MemberService;
 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
 import org.assertj.core.util.Lists;
+import org.dromara.hutool.extra.mail.*;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
@@ -28,8 +27,7 @@ import static cn.hutool.core.util.RandomUtil.randomEle;
 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.*;
 
@@ -61,7 +59,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
 //                .setFrom("奥特曼 <ydym_test@163.com>")
                 .setFrom("ydym_test@163.com") // 邮箱地址
                 .setHost("smtp.163.com").setPort(465).setSslEnable(true) // SMTP 服务器
-                .setAuth(true).setUser("ydym_test@163.com").setPass("WBZTEINMIFVRYSOE"); // 登录账号密码
+                .setAuth(true).setUser("ydym_test@163.com").setPass("WBZTEINMIFVRYSOE".toCharArray()); // 登录账号密码
         String messageId = MailUtil.send(mailAccount, "7685413@qq.com", "主题", "内容", false);
         System.out.println("发送结果:" + messageId);
     }
@@ -268,7 +266,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
 
     @Test
     public void testDoSendMail_success() {
-        try (MockedStatic<MailUtil> mailUtilMock = mockStatic(MailUtil.class)) {
+        try (final MockedStatic<MailUtil> mailUtilMock = mockStatic(MailUtil.class)) {
             // 准备参数
             MailSendMessage message = randomPojo(MailSendMessage.class, o -> o.setNickname("芋艿"));
             // mock 方法(获得邮箱账号)
@@ -283,7 +281,7 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
                         assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom());
                         assertTrue(mailAccount.isAuth());
                         assertEquals(account.getUsername(), mailAccount.getUser());
-                        assertEquals(account.getPassword(), mailAccount.getPass());
+                        assertArrayEquals(account.getPassword().toCharArray(), mailAccount.getPass());
                         assertEquals(account.getHost(), mailAccount.getHost());
                         assertEquals(account.getPort(), mailAccount.getPort());
                         assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
@@ -311,16 +309,15 @@ public class MailSendServiceImplTest extends BaseMockitoUnitTest {
             // mock 方法(发送邮件)
             Exception e = new NullPointerException("啦啦啦");
             mailUtilMock.when(() -> MailUtil.send(argThat(mailAccount -> {
-                        assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom());
-                        assertTrue(mailAccount.isAuth());
-                        assertEquals(account.getUsername(), mailAccount.getUser());
-                        assertEquals(account.getPassword(), mailAccount.getPass());
-                        assertEquals(account.getHost(), mailAccount.getHost());
-                        assertEquals(account.getPort(), mailAccount.getPort());
-                        assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
-                        return true;
-                    }), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true)))
-                    .thenThrow(e);
+                assertEquals("芋艿 <7685@qq.com>", mailAccount.getFrom());
+                assertTrue(mailAccount.isAuth());
+                assertEquals(account.getUsername(), mailAccount.getUser());
+                assertArrayEquals(account.getPassword().toCharArray(), mailAccount.getPass());
+                assertEquals(account.getHost(), mailAccount.getHost());
+                assertEquals(account.getPort(), mailAccount.getPort());
+                assertEquals(account.getSslEnable(), mailAccount.isSslEnable());
+                return true;
+            }), eq(message.getMail()), eq(message.getTitle()), eq(message.getContent()), eq(true))).thenThrow(e);
 
             // 调用
             mailSendService.doSendMail(message);