完善 mail 单元测试

This commit is contained in:
YunaiV 2023-02-03 23:39:38 +08:00
parent 5619441f61
commit 4d42b8834b
6 changed files with 606 additions and 29 deletions

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.service.mail;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount; import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil; import cn.hutool.extra.mail.MailUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert; import cn.iocoder.yudao.module.system.convert.mail.MailAccountConvert;
@ -20,15 +19,13 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/** /**
* 邮箱模版 服务实现类 * 邮箱发送 Service 实现类
* *
* @author wangjingyi * @author wangjingyi
* @since 2022-03-21 * @since 2022-03-21
@ -82,14 +79,13 @@ public class MailSendServiceImpl implements MailSendService {
public Long sendSingleMail(String mail, Long userId, Integer userType, public Long sendSingleMail(String mail, Long userId, Integer userType,
String templateCode, Map<String, Object> templateParams) { String templateCode, Map<String, Object> templateParams) {
// 校验邮箱模版是否合法 // 校验邮箱模版是否合法
MailTemplateDO template = checkMailTemplateValid(templateCode); MailTemplateDO template = validateMailTemplate(templateCode);
// 校验邮箱账号是否合法 // 校验邮箱账号是否合法
MailAccountDO account = checkMailAccountValid(template.getAccountId()); MailAccountDO account = validateMailAccount(template.getAccountId());
// 校验邮箱是否存在 // 校验邮箱是否存在
mail = checkMail(mail); mail = validateMail(mail);
// 校验参数模版 validateTemplateParams(template, templateParams);
checkTemplateParams(template, templateParams);
// 创建发送日志如果模板被禁用则不发送短信只记录日志 // 创建发送日志如果模板被禁用则不发送短信只记录日志
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
@ -107,7 +103,7 @@ public class MailSendServiceImpl implements MailSendService {
@Override @Override
public void doSendMail(MailSendMessage message) { public void doSendMail(MailSendMessage message) {
// 1. 创建发送账号 // 1. 创建发送账号
MailAccountDO account = checkMailAccountValid(message.getAccountId()); MailAccountDO account = validateMailAccount(message.getAccountId());
MailAccount mailAccount = MailAccountConvert.INSTANCE.convert(account, message.getNickname()); MailAccount mailAccount = MailAccountConvert.INSTANCE.convert(account, message.getNickname());
// 2. 发送邮件 // 2. 发送邮件
try { try {
@ -122,7 +118,7 @@ public class MailSendServiceImpl implements MailSendService {
} }
@VisibleForTesting @VisibleForTesting
public MailTemplateDO checkMailTemplateValid(String templateCode) { MailTemplateDO validateMailTemplate(String templateCode) {
// 获得邮件模板考虑到效率从缓存中获取 // 获得邮件模板考虑到效率从缓存中获取
MailTemplateDO template = mailTemplateService.getMailTemplateByCodeFromCache(templateCode); MailTemplateDO template = mailTemplateService.getMailTemplateByCodeFromCache(templateCode);
// 邮件模板不存在 // 邮件模板不存在
@ -133,7 +129,7 @@ public class MailSendServiceImpl implements MailSendService {
} }
@VisibleForTesting @VisibleForTesting
public MailAccountDO checkMailAccountValid(Long accountId) { MailAccountDO validateMailAccount(Long accountId) {
// 获得邮箱账号考虑到效率从缓存中获取 // 获得邮箱账号考虑到效率从缓存中获取
MailAccountDO account = mailAccountService.getMailAccountFromCache(accountId); MailAccountDO account = mailAccountService.getMailAccountFromCache(accountId);
// 邮箱账号不存在 // 邮箱账号不存在
@ -144,7 +140,7 @@ public class MailSendServiceImpl implements MailSendService {
} }
@VisibleForTesting @VisibleForTesting
public String checkMail(String mail) { String validateMail(String mail) {
if (StrUtil.isEmpty(mail)) { if (StrUtil.isEmpty(mail)) {
throw exception(MAIL_SEND_MAIL_NOT_EXISTS); throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
} }
@ -152,13 +148,13 @@ public class MailSendServiceImpl implements MailSendService {
} }
/** /**
* 校验参数模板 * 校验邮件参数是否确实
* *
* @param template 邮箱模板 * @param template 邮箱模板
* @param templateParams 原始参数 * @param templateParams 参数列表
*/ */
@VisibleForTesting @VisibleForTesting
public void checkTemplateParams(MailTemplateDO template, Map<String, Object> templateParams) { void validateTemplateParams(MailTemplateDO template, Map<String, Object> templateParams) {
template.getParams().forEach(key -> { template.getParams().forEach(key -> {
Object value = templateParams.get(key); Object value = templateParams.get(key);
if (value == null) { if (value == null) {

View File

@ -13,6 +13,7 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
import java.util.Map; import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
@ -21,7 +22,9 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_ACCOUNT_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/** /**
* {@link MailAccountServiceImpl} 的单元测试类 * {@link MailAccountServiceImpl} 的单元测试类
@ -107,6 +110,8 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest {
mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据 mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据
// 准备参数 // 准备参数
Long id = dbMailAccount.getId(); Long id = dbMailAccount.getId();
// mock 方法无关联模版
when(mailTemplateService.countByAccountId(eq(id))).thenReturn(0L);
// 调用 // 调用
mailAccountService.deleteMailAccount(id); mailAccountService.deleteMailAccount(id);
@ -115,6 +120,21 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest {
verify(mailProducer).sendMailAccountRefreshMessage(); verify(mailProducer).sendMailAccountRefreshMessage();
} }
@Test
public void testGetMailAccountFromCache() {
// mock 数据
MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class);
mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据
mailAccountService.initLocalCache();
// 准备参数
Long id = dbMailAccount.getId();
// 调用
MailAccountDO mailAccount = mailAccountService.getMailAccountFromCache(id);
// 断言
assertPojoEquals(dbMailAccount, mailAccount);
}
@Test @Test
public void testDeleteMailAccount_notExists() { public void testDeleteMailAccount_notExists() {
// 准备参数 // 准备参数
@ -149,4 +169,35 @@ public class MailAccountServiceImplTest extends BaseDbUnitTest {
assertPojoEquals(dbMailAccount, pageResult.getList().get(0)); assertPojoEquals(dbMailAccount, pageResult.getList().get(0));
} }
@Test
public void testGetMailAccount() {
// mock 数据
MailAccountDO dbMailAccount = randomPojo(MailAccountDO.class);
mailAccountMapper.insert(dbMailAccount);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbMailAccount.getId();
// 调用
MailAccountDO mailAccount = mailAccountService.getMailAccount(id);
// 断言
assertPojoEquals(dbMailAccount, mailAccount);
}
@Test
public void testGetMailAccountList() {
// mock 数据
MailAccountDO dbMailAccount01 = randomPojo(MailAccountDO.class);
mailAccountMapper.insert(dbMailAccount01);
MailAccountDO dbMailAccount02 = randomPojo(MailAccountDO.class);
mailAccountMapper.insert(dbMailAccount02);
// 准备参数
// 调用
List<MailAccountDO> list = mailAccountService.getMailAccountList();
// 断言
assertEquals(2, list.size());
assertPojoEquals(dbMailAccount01, list.get(0));
assertPojoEquals(dbMailAccount02, list.get(1));
}
} }

View File

@ -116,6 +116,20 @@ public class MailLogServiceImplTest extends BaseDbUnitTest {
assertEquals("NullPointerException: 测试异常", dbLog.getSendException()); assertEquals("NullPointerException: 测试异常", dbLog.getSendException());
} }
@Test
public void testGetMailLog() {
// mock 数据
MailLogDO dbMailLog = randomPojo(MailLogDO.class, o -> o.setTemplateParams(randomTemplateParams()));
mailLogMapper.insert(dbMailLog);
// 准备参数
Long id = dbMailLog.getId();
// 调用
MailLogDO mailLog = mailLogService.getMailLog(id);
// 断言
assertPojoEquals(dbMailLog, mailLog);
}
@Test @Test
public void testGetMailLogPage() { public void testGetMailLogPage() {
// mock 数据 // mock 数据

View File

@ -6,14 +6,20 @@ import cn.hutool.extra.mail.MailUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO; 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.mail.MailTemplateDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
import cn.iocoder.yudao.module.system.mq.producer.mail.MailProducer; 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.assertj.core.util.Lists;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockedStatic;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -23,6 +29,7 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -31,6 +38,10 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks @InjectMocks
private MailSendServiceImpl mailSendService; private MailSendServiceImpl mailSendService;
@Mock
private AdminUserService adminUserService;
@Mock
private MemberService memberService;
@Mock @Mock
private MailAccountService mailAccountService; private MailAccountService mailAccountService;
@Mock @Mock
@ -55,6 +66,82 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
System.out.println("发送结果:" + messageId); System.out.println("发送结果:" + messageId);
} }
@Test
public void testSendSingleMailToAdmin() {
// 准备参数
Long userId = randomLongId();
String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock adminUserService 的方法
AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setMobile("15601691300"));
when(adminUserService.getUser(eq(userId))).thenReturn(user);
// mock MailTemplateService 的方法
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = RandomUtils.randomString();
when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock MailAccountService 的方法
MailAccountDO account = randomPojo(MailAccountDO.class);
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
// mock MailLogService 的方法
Long mailLogId = randomLongId();
when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.ADMIN.getValue()), eq(user.getEmail()),
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
// 调用
Long resultMailLogId = mailSendService.sendSingleMailToAdmin(null, userId, templateCode, templateParams);
// 断言
assertEquals(mailLogId, resultMailLogId);
// 断言调用
verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(user.getEmail()),
eq(account.getId()), eq(template.getNickname()), eq(template.getTitle()), eq(content));
}
@Test
public void testSendSingleMailToMember() {
// 准备参数
Long userId = randomLongId();
String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock memberService 的方法
String mail = randomEmail();
when(memberService.getMemberUserEmail(eq(userId))).thenReturn(mail);
// mock MailTemplateService 的方法
MailTemplateDO template = randomPojo(MailTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = RandomUtils.randomString();
when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock MailAccountService 的方法
MailAccountDO account = randomPojo(MailAccountDO.class);
when(mailAccountService.getMailAccountFromCache(eq(template.getAccountId()))).thenReturn(account);
// mock MailLogService 的方法
Long mailLogId = randomLongId();
when(mailLogService.createMailLog(eq(userId), eq(UserTypeEnum.MEMBER.getValue()), eq(mail),
eq(account), eq(template), eq(content), eq(templateParams), eq(true))).thenReturn(mailLogId);
// 调用
Long resultMailLogId = mailSendService.sendSingleMailToMember(null, userId, templateCode, templateParams);
// 断言
assertEquals(mailLogId, resultMailLogId);
// 断言调用
verify(mailProducer).sendMailSendMessage(eq(mailLogId), eq(mail),
eq(account.getId()), eq(template.getNickname()), eq(template.getTitle()), eq(content));
}
/** /**
* 发送成功当短信模板开启时 * 发送成功当短信模板开启时
*/ */
@ -64,7 +151,7 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
String mail = randomEmail(); String mail = randomEmail();
Long userId = randomLongId(); Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue(); Integer userType = randomEle(UserTypeEnum.values()).getValue();
String templateCode = randomString(); String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234") Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build(); .put("op", "login").build();
// mock MailTemplateService 的方法 // mock MailTemplateService 的方法
@ -74,7 +161,7 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
o.setParams(Lists.newArrayList("code", "op")); o.setParams(Lists.newArrayList("code", "op"));
}); });
when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = randomString(); String content = RandomUtils.randomString();
when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams))) when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content); .thenReturn(content);
// mock MailAccountService 的方法 // mock MailAccountService 的方法
@ -103,7 +190,7 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
String mail = randomEmail(); String mail = randomEmail();
Long userId = randomLongId(); Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue(); Integer userType = randomEle(UserTypeEnum.values()).getValue();
String templateCode = randomString(); String templateCode = RandomUtils.randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234") Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build(); .put("op", "login").build();
// mock MailTemplateService 的方法 // mock MailTemplateService 的方法
@ -113,7 +200,7 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
o.setParams(Lists.newArrayList("code", "op")); o.setParams(Lists.newArrayList("code", "op"));
}); });
when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template); when(mailTemplateService.getMailTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = randomString(); String content = RandomUtils.randomString();
when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams))) when(mailTemplateService.formatMailTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content); .thenReturn(content);
// mock MailAccountService 的方法 // mock MailAccountService 的方法
@ -134,18 +221,18 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
} }
@Test @Test
public void testCheckMailTemplateValid_notExists() { public void testValidateMailTemplateValid_notExists() {
// 准备参数 // 准备参数
String templateCode = randomString(); String templateCode = RandomUtils.randomString();
// mock 方法 // mock 方法
// 调用并断言异常 // 调用并断言异常
assertServiceException(() -> mailSendService.checkMailTemplateValid(templateCode), assertServiceException(() -> mailSendService.validateMailTemplate(templateCode),
MAIL_TEMPLATE_NOT_EXISTS); MAIL_TEMPLATE_NOT_EXISTS);
} }
@Test @Test
public void testBuildTemplateParams_paramMiss() { public void testValidateTemplateParams_paramMiss() {
// 准备参数 // 准备参数
MailTemplateDO template = randomPojo(MailTemplateDO.class, MailTemplateDO template = randomPojo(MailTemplateDO.class,
o -> o.setParams(Lists.newArrayList("code"))); o -> o.setParams(Lists.newArrayList("code")));
@ -153,18 +240,80 @@ class MailSendServiceImplTest extends BaseMockitoUnitTest {
// mock 方法 // mock 方法
// 调用并断言异常 // 调用并断言异常
assertServiceException(() -> mailSendService.checkTemplateParams(template, templateParams), assertServiceException(() -> mailSendService.validateTemplateParams(template, templateParams),
MAIL_SEND_TEMPLATE_PARAM_MISS, "code"); MAIL_SEND_TEMPLATE_PARAM_MISS, "code");
} }
@Test @Test
public void testCheckMail_notExists() { public void testValidateMail_notExists() {
// 准备参数 // 准备参数
// mock 方法 // mock 方法
// 调用并断言异常 // 调用并断言异常
assertServiceException(() -> mailSendService.checkMail(null), assertServiceException(() -> mailSendService.validateMail(null),
MAIL_SEND_MAIL_NOT_EXISTS); MAIL_SEND_MAIL_NOT_EXISTS);
} }
@Test
public void testDoSendMail_success() {
try (MockedStatic<MailUtil> mailUtilMock = mockStatic(MailUtil.class)) {
// 准备参数
MailSendMessage message = randomPojo(MailSendMessage.class, o -> o.setNickname("芋艿"));
// mock 方法获得邮箱账号
MailAccountDO account = randomPojo(MailAccountDO.class, o -> o.setMail("7685@qq.com"));
when(mailAccountService.getMailAccountFromCache(eq(message.getAccountId())))
.thenReturn(account);
// mock 方法发送邮件
String messageId = randomString();
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)))
.thenReturn(messageId);
// 调用
mailSendService.doSendMail(message);
// 断言
verify(mailLogService).updateMailSendResult(eq(message.getLogId()), eq(messageId), isNull());
}
}
@Test
public void testDoSendMail_exception() {
try (MockedStatic<MailUtil> mailUtilMock = mockStatic(MailUtil.class)) {
// 准备参数
MailSendMessage message = randomPojo(MailSendMessage.class, o -> o.setNickname("芋艿"));
// mock 方法获得邮箱账号
MailAccountDO account = randomPojo(MailAccountDO.class, o -> o.setMail("7685@qq.com"));
when(mailAccountService.getMailAccountFromCache(eq(message.getAccountId())))
.thenReturn(account);
// 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);
// 调用
mailSendService.doSendMail(message);
// 断言
verify(mailLogService).updateMailSendResult(eq(message.getLogId()), isNull(), same(e));
}
}
} }

View File

@ -14,6 +14,8 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
@ -25,6 +27,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.verify;
/** /**
* {@link MailTemplateServiceImpl} 的单元测试类 * {@link MailTemplateServiceImpl} 的单元测试类
@ -70,6 +73,7 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
// 校验记录的属性是否正确 // 校验记录的属性是否正确
MailTemplateDO mailTemplate = mailTemplateMapper.selectById(mailTemplateId); MailTemplateDO mailTemplate = mailTemplateMapper.selectById(mailTemplateId);
assertPojoEquals(reqVO, mailTemplate); assertPojoEquals(reqVO, mailTemplate);
verify(mailProducer).sendMailTemplateRefreshMessage();
} }
@Test @Test
@ -87,6 +91,7 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
// 校验是否更新正确 // 校验是否更新正确
MailTemplateDO mailTemplate = mailTemplateMapper.selectById(reqVO.getId()); // 获取最新的 MailTemplateDO mailTemplate = mailTemplateMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, mailTemplate); assertPojoEquals(reqVO, mailTemplate);
verify(mailProducer).sendMailTemplateRefreshMessage();
} }
@Test @Test
@ -108,8 +113,9 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
// 调用 // 调用
mailTemplateService.deleteMailTemplate(id); mailTemplateService.deleteMailTemplate(id);
// 校验数据不存在了 // 校验数据不存在了
assertNull(mailTemplateMapper.selectById(id)); assertNull(mailTemplateMapper.selectById(id));
verify(mailProducer).sendMailTemplateRefreshMessage();
} }
@Test @Test
@ -158,4 +164,77 @@ public class MailTemplateServiceImplTest extends BaseDbUnitTest {
assertPojoEquals(dbMailTemplate, pageResult.getList().get(0)); assertPojoEquals(dbMailTemplate, pageResult.getList().get(0));
} }
@Test
public void testGetMailTemplateList() {
// mock 数据
MailTemplateDO dbMailTemplate01 = randomPojo(MailTemplateDO.class);
mailTemplateMapper.insert(dbMailTemplate01);
MailTemplateDO dbMailTemplate02 = randomPojo(MailTemplateDO.class);
mailTemplateMapper.insert(dbMailTemplate02);
// 调用
List<MailTemplateDO> list = mailTemplateService.getMailTemplateList();
// 断言
assertEquals(2, list.size());
assertEquals(dbMailTemplate01, list.get(0));
assertEquals(dbMailTemplate02, list.get(1));
}
@Test
public void testGetTemplate() {
// mock 数据
MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class);
mailTemplateMapper.insert(dbMailTemplate);
// 准备参数
Long id = dbMailTemplate.getId();
// 调用
MailTemplateDO mailTemplate = mailTemplateService.getMailTemplate(id);
// 断言
assertPojoEquals(dbMailTemplate, mailTemplate);
}
@Test
public void testGetMailTemplateByCodeFromCache() {
// mock 数据
MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class);
mailTemplateMapper.insert(dbMailTemplate);
mailTemplateService.initLocalCache();
// 准备参数
String code = dbMailTemplate.getCode();
// 调用
MailTemplateDO mailTemplate = mailTemplateService.getMailTemplateByCodeFromCache(code);
// 断言
assertPojoEquals(dbMailTemplate, mailTemplate);
}
@Test
public void testFormatMailTemplateContent() {
// 准备参数
Map<String, Object> params = new HashMap<>();
params.put("name", "小红");
params.put("what", "");
// 调用并断言
assertEquals("小红,你好,饭吃了吗?",
mailTemplateService.formatMailTemplateContent("{name},你好,{what}吃了吗?", params));
}
@Test
public void testCountByAccountId() {
// mock 数据
MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class);
mailTemplateMapper.insert(dbMailTemplate);
// 测试 accountId 不匹配
mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setAccountId(2L)));
// 准备参数
Long accountId = dbMailTemplate.getAccountId();
// 调用
long count = mailTemplateService.countByAccountId(accountId);
// 断言
assertEquals(1, count);
}
} }

View File

@ -0,0 +1,288 @@
package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
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.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
@InjectMocks
private SmsSendServiceImpl smsService;
@Mock
private AdminUserService adminUserService;
@Mock
private MemberService memberService;
@Mock
private SmsChannelService smsChannelService;
@Mock
private SmsTemplateService smsTemplateService;
@Mock
private SmsLogService smsLogService;
@Mock
private SmsProducer smsProducer;
@Mock
private SmsClientFactory smsClientFactory;
@Test
public void testSendSingleSmsToAdmin() {
// 准备参数
Long userId = randomLongId();
String templateCode = randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock adminUserService 的方法
AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setMobile("15601691300"));
when(adminUserService.getUser(eq(userId))).thenReturn(user);
// mock SmsTemplateService 的方法
SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = randomString();
when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock SmsChannelService 的方法
SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel);
// mock SmsLogService 的方法
Long smsLogId = randomLongId();
when(smsLogService.createSmsLog(eq(user.getMobile()), eq(userId), eq(UserTypeEnum.ADMIN.getValue()), eq(Boolean.TRUE), eq(template),
eq(content), eq(templateParams))).thenReturn(smsLogId);
// 调用
Long resultSmsLogId = smsService.sendSingleSmsToAdmin(null, userId, templateCode, templateParams);
// 断言
assertEquals(smsLogId, resultSmsLogId);
// 断言调用
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(user.getMobile()),
eq(template.getChannelId()), eq(template.getApiTemplateId()),
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
}
@Test
public void testSendSingleSmsToUser() {
// 准备参数
Long userId = randomLongId();
String templateCode = randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock memberService 的方法
String mobile = "15601691300";
when(memberService.getMemberUserMobile(eq(userId))).thenReturn(mobile);
// mock SmsTemplateService 的方法
SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = randomString();
when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock SmsChannelService 的方法
SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel);
// mock SmsLogService 的方法
Long smsLogId = randomLongId();
when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(UserTypeEnum.MEMBER.getValue()), eq(Boolean.TRUE), eq(template),
eq(content), eq(templateParams))).thenReturn(smsLogId);
// 调用
Long resultSmsLogId = smsService.sendSingleSmsToMember(null, userId, templateCode, templateParams);
// 断言
assertEquals(smsLogId, resultSmsLogId);
// 断言调用
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile),
eq(template.getChannelId()), eq(template.getApiTemplateId()),
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
}
/**
* 发送成功当短信模板开启时
*/
@Test
public void testSendSingleSms_successWhenSmsTemplateEnable() {
// 准备参数
String mobile = randomString();
Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue();
String templateCode = randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock SmsTemplateService 的方法
SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = randomString();
when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock SmsChannelService 的方法
SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel);
// mock SmsLogService 的方法
Long smsLogId = randomLongId();
when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(userType), eq(Boolean.TRUE), eq(template),
eq(content), eq(templateParams))).thenReturn(smsLogId);
// 调用
Long resultSmsLogId = smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
// 断言
assertEquals(smsLogId, resultSmsLogId);
// 断言调用
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile),
eq(template.getChannelId()), eq(template.getApiTemplateId()),
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
}
/**
* 发送成功当短信模板关闭时
*/
@Test
public void testSendSingleSms_successWhenSmsTemplateDisable() {
// 准备参数
String mobile = randomString();
Long userId = randomLongId();
Integer userType = randomEle(UserTypeEnum.values()).getValue();
String templateCode = randomString();
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
.put("op", "login").build();
// mock SmsTemplateService 的方法
SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> {
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
o.setContent("验证码为{code}, 操作为{op}");
o.setParams(Lists.newArrayList("code", "op"));
});
when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
String content = randomString();
when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
.thenReturn(content);
// mock SmsChannelService 的方法
SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel);
// mock SmsLogService 的方法
Long smsLogId = randomLongId();
when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(userType), eq(Boolean.FALSE), eq(template),
eq(content), eq(templateParams))).thenReturn(smsLogId);
// 调用
Long resultSmsLogId = smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
// 断言
assertEquals(smsLogId, resultSmsLogId);
// 断言调用
verify(smsProducer, times(0)).sendSmsSendMessage(anyLong(), anyString(),
anyLong(), any(), anyList());
}
@Test
public void testCheckSmsTemplateValid_notExists() {
// 准备参数
String templateCode = randomString();
// mock 方法
// 调用并断言异常
assertServiceException(() -> smsService.validateSmsTemplate(templateCode),
SMS_SEND_TEMPLATE_NOT_EXISTS);
}
@Test
public void testBuildTemplateParams_paramMiss() {
// 准备参数
SmsTemplateDO template = randomPojo(SmsTemplateDO.class,
o -> o.setParams(Lists.newArrayList("code")));
Map<String, Object> templateParams = new HashMap<>();
// mock 方法
// 调用并断言异常
assertServiceException(() -> smsService.buildTemplateParams(template, templateParams),
SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, "code");
}
@Test
public void testCheckMobile_notExists() {
// 准备参数
// mock 方法
// 调用并断言异常
assertServiceException(() -> smsService.validateMobile(null),
SMS_SEND_MOBILE_NOT_EXISTS);
}
@Test
@SuppressWarnings("unchecked")
public void testDoSendSms() {
// 准备参数
SmsSendMessage message = randomPojo(SmsSendMessage.class);
// mock SmsClientFactory 的方法
SmsClient smsClient = spy(SmsClient.class);
when(smsClientFactory.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient);
// mock SmsClient 的方法
SmsCommonResult<SmsSendRespDTO> sendResult = randomPojo(SmsCommonResult.class, SmsSendRespDTO.class);
when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()),
eq(message.getTemplateParams()))).thenReturn(sendResult);
// 调用
smsService.doSendSms(message);
// 断言
verify(smsLogService).updateSmsSendResult(eq(message.getLogId()),
eq(sendResult.getCode()), eq(sendResult.getMsg()), eq(sendResult.getApiCode()),
eq(sendResult.getApiMsg()), eq(sendResult.getApiRequestId()), eq(sendResult.getData().getSerialNo()));
}
@Test
public void testReceiveSmsStatus() throws Throwable {
// 准备参数
String channelCode = randomString();
String text = randomString();
// mock SmsClientFactory 的方法
SmsClient smsClient = spy(SmsClient.class);
when(smsClientFactory.getSmsClient(eq(channelCode))).thenReturn(smsClient);
// mock SmsClient 的方法
List<SmsReceiveRespDTO> receiveResults = randomPojoList(SmsReceiveRespDTO.class);
// 调用
smsService.receiveSmsStatus(channelCode, text);
// 断言
receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()),
eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorCode())));
}
}