package cn.iocoder.yudao.module.system.service.mail; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplateSaveReqVO; import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.MailTemplatePageReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO; import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; import jakarta.annotation.Resource; import java.util.HashMap; import java.util.List; 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.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 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.module.system.enums.ErrorCodeConstants.MAIL_TEMPLATE_NOT_EXISTS; import static org.junit.jupiter.api.Assertions.*; /** * {@link MailTemplateServiceImpl} 的单元测试类 * * @author 芋道源码 */ @Import(MailTemplateServiceImpl.class) public class MailTemplateServiceImplTest extends BaseDbUnitTest { @Resource private MailTemplateServiceImpl mailTemplateService; @Resource private MailTemplateMapper mailTemplateMapper; @Test public void testCreateMailTemplate_success() { // 准备参数 MailTemplateSaveReqVO reqVO = randomPojo(MailTemplateSaveReqVO.class) .setId(null); // 防止 id 被赋值 // 调用 Long mailTemplateId = mailTemplateService.createMailTemplate(reqVO); // 断言 assertNotNull(mailTemplateId); // 校验记录的属性是否正确 MailTemplateDO mailTemplate = mailTemplateMapper.selectById(mailTemplateId); assertPojoEquals(reqVO, mailTemplate, "id"); } @Test public void testUpdateMailTemplate_success() { // mock 数据 MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class); mailTemplateMapper.insert(dbMailTemplate);// @Sql: 先插入出一条存在的数据 // 准备参数 MailTemplateSaveReqVO reqVO = randomPojo(MailTemplateSaveReqVO.class, o -> { o.setId(dbMailTemplate.getId()); // 设置更新的 ID }); // 调用 mailTemplateService.updateMailTemplate(reqVO); // 校验是否更新正确 MailTemplateDO mailTemplate = mailTemplateMapper.selectById(reqVO.getId()); // 获取最新的 assertPojoEquals(reqVO, mailTemplate); } @Test public void testUpdateMailTemplate_notExists() { // 准备参数 MailTemplateSaveReqVO reqVO = randomPojo(MailTemplateSaveReqVO.class); // 调用, 并断言异常 assertServiceException(() -> mailTemplateService.updateMailTemplate(reqVO), MAIL_TEMPLATE_NOT_EXISTS); } @Test public void testDeleteMailTemplate_success() { // mock 数据 MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class); mailTemplateMapper.insert(dbMailTemplate);// @Sql: 先插入出一条存在的数据 // 准备参数 Long id = dbMailTemplate.getId(); // 调用 mailTemplateService.deleteMailTemplate(id); // 校验数据不存在了 assertNull(mailTemplateMapper.selectById(id)); } @Test public void testDeleteMailTemplate_notExists() { // 准备参数 Long id = randomLongId(); // 调用, 并断言异常 assertServiceException(() -> mailTemplateService.deleteMailTemplate(id), MAIL_TEMPLATE_NOT_EXISTS); } @Test public void testGetMailTemplatePage() { // mock 数据 MailTemplateDO dbMailTemplate = randomPojo(MailTemplateDO.class, o -> { // 等会查询到 o.setName("源码"); o.setCode("test_01"); o.setAccountId(1L); o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setCreateTime(buildTime(2023, 2, 3)); }); mailTemplateMapper.insert(dbMailTemplate); // 测试 name 不匹配 mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setName("芋道"))); // 测试 code 不匹配 mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setCode("test_02"))); // 测试 accountId 不匹配 mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setAccountId(2L))); // 测试 status 不匹配 mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); // 测试 createTime 不匹配 mailTemplateMapper.insert(cloneIgnoreId(dbMailTemplate, o -> o.setCreateTime(buildTime(2023, 1, 5)))); // 准备参数 MailTemplatePageReqVO reqVO = new MailTemplatePageReqVO(); reqVO.setName("源"); reqVO.setCode("est_01"); reqVO.setAccountId(1L); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 5)); // 调用 PageResult pageResult = mailTemplateService.getMailTemplatePage(reqVO); // 断言 assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getList().size()); 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 list = mailTemplateService.getMailTemplateList(); // 断言 assertEquals(2, list.size()); assertEquals(dbMailTemplate01, list.get(0)); assertEquals(dbMailTemplate02, list.get(1)); } @Test public void testGetMailTemplate() { // 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); // 准备参数 String code = dbMailTemplate.getCode(); // 调用 MailTemplateDO mailTemplate = mailTemplateService.getMailTemplateByCodeFromCache(code); // 断言 assertPojoEquals(dbMailTemplate, mailTemplate); } @Test public void testFormatMailTemplateContent() { // 准备参数 Map params = new HashMap<>(); params.put("name", "小红"); params.put("what", "饭"); // 调用,并断言 assertEquals("小红,你好,饭吃了吗?", mailTemplateService.formatMailTemplateContent("{name},你好,{what}吃了吗?", params)); } @Test public void testFormatMailTemplateContent_htmlUnescape() { // 准备参数 Map params = new HashMap<>(); params.put("title", "测试标题"); // 测试HTML反转义 String content = "

{title}

<p>这是一个测试</p>&nbsp;空格"; String expected = "

测试标题

这是一个测试

空格"; // 调用,并断言 assertEquals(expected, mailTemplateService.formatMailTemplateContent(content, params)); } @Test public void testFormatMailTemplateContent_codeBlockFormatting() { // 准备参数 Map params = new HashMap<>(); params.put("name", "测试"); // 测试代码块格式化 String content = "
public class Test {\n    public static void main(String[] args) {\n        System.out.println(\"Hello {name}\"));\n    }\n}
"; // 调用,并断言结果 String result = mailTemplateService.formatMailTemplateContent(content, params); // 断言 pre 标签被替换为 div 标签 assertTrue(result.contains("
public class Test {")); assertTrue(result.contains("System.out.println(\"Hello 测试\"")); assertTrue(result.contains("
")); } @Test public void testFormatMailTemplateContent_preToDiv() { // 准备参数 Map params = new HashMap<>(); params.put("content", "测试内容"); // 测试 pre 标签替换为 div 标签 String content = "
{content}
"; String result = mailTemplateService.formatMailTemplateContent(content, params); // 断言结果中包含 div 标签,而不包含 pre 标签 assertTrue(result.contains("
测试内容
")); } @Test public void testFormatMailTemplateContent_completeHtml() { // 准备参数 Map params = new HashMap<>(); params.put("username", "testuser"); params.put("company", "测试公司"); // 测试完整的 HTML 邮件模板 String content = "\n \n \n \n \n Title\n \n \n
\n \n
\n
\n
\n
\n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n \n \n \n
\n
此邮件由系统发出,请勿直接回复或转发他人
\n

\n
\n \n \n \n \n \n \n \n \n
\n

\n 尊敬的 {username},\n

\n
\n
\n

\n 内容
\n 内容
\n 内容123

\n\n 如果您在使用过程中遇到任何问题或者有任何建议,都可以随时联系我们的客户团队,我们将竭诚为您服务。\n\n\n\n\n
\n
\n {company}
\n 地址:xxxxx
\n 邮箱:lambc77@163.com\n

\n
\n
\n
\n
\n
\n 声明:本邮件含有保密信息,仅限于收件人所用。禁止任何人未经发件人许可,以任何形式(包括但不限于部分的泄露、复制或散发)不当的使用本邮件中的信息。如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件,谢谢!\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n \n "; // 调用,并断言成功处理 String result = mailTemplateService.formatMailTemplateContent(content, params); // 断言结果中包含替换后的变量 assertTrue(result.contains("尊敬的 testuser")); assertTrue(result.contains("测试公司")); // 断言结果是有效的 HTML assertTrue(result.startsWith("")); } @Test public void testFormatMailTemplateContent_emptyContent() { // 准备参数 Map params = new HashMap<>(); // 测试空内容 String result = mailTemplateService.formatMailTemplateContent("", params); assertEquals("", result); } @Test public void testFormatMailTemplateContent_noParams() { // 准备参数 Map params = new HashMap<>(); // 测试没有参数需要替换的情况 String content = "
System.out.println(\"Hello World\");
"; String result = mailTemplateService.formatMailTemplateContent(content, params); assertTrue(result.contains("
System.out.println(\"Hello World\");
")); } @Test public void testFormatMailTemplateContent_multiplePreTags() { // 准备参数 Map params = new HashMap<>(); params.put("param1", "value1"); params.put("param2", "value2"); // 测试多个 pre 标签的情况 String content = "
First code block: {param1}
\n" + "

Some text between code blocks

\n" + "
Second code block: {param2}
"; String result = mailTemplateService.formatMailTemplateContent(content, params); // 断言两个pre标签都被替换为div标签 assertTrue(result.contains("
First code block: value1
")); assertTrue(result.contains("
Second code block: value2
")); } @Test public void testFormatMailTemplateContent_specialCharacters() { // 准备参数 Map params = new HashMap<>(); // 简化测试,只测试基本的 HTML 特殊字符 String content = "<div>测试 & 特殊字符</div>"; String result = mailTemplateService.formatMailTemplateContent(content, params); // 断言特殊字符被正确反转义 assertTrue(result.contains("
测试 & 特殊字符
")); } @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.getMailTemplateCountByAccountId(accountId); // 断言 assertEquals(1, count); } @Test public void testDifferenceWithHtmlContent() { // 准备包含 HTML 格式的模板内容 String content = "
" + "

Welcome, {username}!

" + "

Your account has been created successfully.

" + "
" + "Account Details:
" + "Username: {username}
" + "Email: {email}
" + "Role: {role}
" + "
" + "

Please click here to activate your account.

" + "
public class WelcomeMessage {\n    public static void main(String[] args) {\n        System.out.println(\"Hello {username}!\");\n    }\n}
" + "
"; Map params = new HashMap<>(); params.put("username", "testuser"); params.put("email", "test@163.com"); params.put("role", "admin"); params.put("activationLink", "https://example.com/activate?code=12345"); // 1. 使用 parseTemplateContentParams:只提取参数名称,忽略了 HTML 格式 List parsedParams = mailTemplateService.parseTemplateContentParams(content); System.out.println("parseTemplateContentParams结果:" + parsedParams); // 断言:只提取了纯参数名称,没有 HTML 格式 assertEquals(6, parsedParams.size()); // 检查所有参数类型 assertEquals(3, parsedParams.stream().filter("username"::equals).count()); assertEquals(1, parsedParams.stream().filter("email"::equals).count()); assertEquals(1, parsedParams.stream().filter("role"::equals).count()); assertEquals(1, parsedParams.stream().filter("activationLink"::equals).count()); // 断言:没有包含任何 HTML 标签 for (String param : parsedParams) { assertFalse(param.contains("<")); assertFalse(param.contains(">")); } // 2. 使用 formatMailTemplateContent:处理 HTML 格式,生成最终内容 String formattedContent = mailTemplateService.formatMailTemplateContent(content, params); System.out.println("formatMailTemplateContent结果:" + formattedContent); // 断言:HTML 格式被保留并处理 assertTrue(formattedContent.contains("
")); assertTrue(formattedContent.contains("

Welcome, testuser!

")); assertTrue(formattedContent.contains("here")); assertTrue(formattedContent.contains("
public class WelcomeMessage {")); assertTrue(formattedContent.contains("
")); // 断言:所有参数都被正确替换 assertFalse(formattedContent.contains("{username}")); assertFalse(formattedContent.contains("{email}")); assertFalse(formattedContent.contains("{role}")); assertFalse(formattedContent.contains("{activationLink}")); } }