完善 SmsCodeServiceImpl 单元测试

This commit is contained in:
YunaiV 2023-02-02 23:16:43 +08:00
parent 5a18223bc3
commit ac25dbe286
12 changed files with 416 additions and 481 deletions

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.api.sms; package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.enums.ApiConstants; import cn.iocoder.yudao.module.system.enums.ApiConstants;
@ -29,8 +29,8 @@ public interface SmsCodeApi {
@ApiOperation("验证短信验证码,并进行使用") @ApiOperation("验证短信验证码,并进行使用")
CommonResult<Boolean> useSmsCode(@Valid @RequestBody SmsCodeUseReqDTO reqDTO); CommonResult<Boolean> useSmsCode(@Valid @RequestBody SmsCodeUseReqDTO reqDTO);
@GetMapping(PREFIX + "/check") @GetMapping(PREFIX + "/validate")
@ApiOperation("检查验证码是否有效") @ApiOperation("检查验证码是否有效")
CommonResult<Boolean> checkSmsCode(@Valid @RequestBody SmsCodeCheckReqDTO reqDTO); CommonResult<Boolean> validateSmsCode(@Valid @RequestBody SmsCodeValidateReqDTO reqDTO);
} }

View File

@ -12,7 +12,7 @@ import javax.validation.constraints.NotNull;
@ApiModel("RPC 服务 - 短信验证码的校验 Request DTO") @ApiModel("RPC 服务 - 短信验证码的校验 Request DTO")
@Data @Data
public class SmsCodeCheckReqDTO { public class SmsCodeValidateReqDTO {
@ApiModelProperty(value = "手机号", required = true, example = "15601691300") @ApiModelProperty(value = "手机号", required = true, example = "15601691300")
@Mobile @Mobile

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.api.sms; package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.service.sms.SmsCodeService; import cn.iocoder.yudao.module.system.service.sms.SmsCodeService;
@ -35,8 +35,8 @@ public class SmsCodeApiImpl implements SmsCodeApi {
} }
@Override @Override
public CommonResult<Boolean> checkSmsCode(SmsCodeCheckReqDTO reqDTO) { public CommonResult<Boolean> validateSmsCode(SmsCodeValidateReqDTO reqDTO) {
smsCodeService.checkSmsCode(reqDTO); smsCodeService.validateSmsCode(reqDTO);
return success(true); return success(true);
} }

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.system.service.sms; package cn.iocoder.yudao.module.system.service.sms;
import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import javax.validation.Valid; import javax.validation.Valid;
@ -35,6 +35,6 @@ public interface SmsCodeService {
* *
* @param reqDTO 校验请求 * @param reqDTO 校验请求
*/ */
void checkSmsCode(@Valid SmsCodeCheckReqDTO reqDTO); void validateSmsCode(@Valid SmsCodeValidateReqDTO reqDTO);
} }

View File

@ -3,11 +3,9 @@ package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO; import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO;
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper; import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
@ -16,11 +14,11 @@ 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.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import static cn.hutool.core.util.RandomUtil.randomInt; import static cn.hutool.core.util.RandomUtil.randomInt;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.isToday;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/** /**
@ -58,11 +56,11 @@ public class SmsCodeServiceImpl implements SmsCodeService {
if (lastSmsCode != null) { if (lastSmsCode != null) {
if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis()
< smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁 < smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁
throw ServiceExceptionUtil.exception(SMS_CODE_SEND_TOO_FAST); throw exception(SMS_CODE_SEND_TOO_FAST);
} }
if (DateUtils.isToday(lastSmsCode.getCreateTime()) && // 必须是今天才能计算超过当天的上限 if (isToday(lastSmsCode.getCreateTime()) && // 必须是今天才能计算超过当天的上限
lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限 lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限
throw ServiceExceptionUtil.exception(SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); throw exception(SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
} }
// TODO 芋艿提升每个 IP 每天可发送数量 // TODO 芋艿提升每个 IP 每天可发送数量
// TODO 芋艿提升每个 IP 每小时可发送数量 // TODO 芋艿提升每个 IP 每小时可发送数量
@ -71,7 +69,7 @@ public class SmsCodeServiceImpl implements SmsCodeService {
// 创建验证码记录 // 创建验证码记录
String code = String.valueOf(randomInt(smsCodeProperties.getBeginCode(), smsCodeProperties.getEndCode() + 1)); String code = String.valueOf(randomInt(smsCodeProperties.getBeginCode(), smsCodeProperties.getEndCode() + 1));
SmsCodeDO newSmsCode = SmsCodeDO.builder().mobile(mobile).code(code).scene(scene) SmsCodeDO newSmsCode = SmsCodeDO.builder().mobile(mobile).code(code).scene(scene)
.todayIndex(lastSmsCode != null && DateUtils.isToday(lastSmsCode.getCreateTime()) ? lastSmsCode.getTodayIndex() + 1 : 1) .todayIndex(lastSmsCode != null && isToday(lastSmsCode.getCreateTime()) ? lastSmsCode.getTodayIndex() + 1 : 1)
.createIp(ip).used(false).build(); .createIp(ip).used(false).build();
smsCodeMapper.insert(newSmsCode); smsCodeMapper.insert(newSmsCode);
return code; return code;
@ -80,32 +78,32 @@ public class SmsCodeServiceImpl implements SmsCodeService {
@Override @Override
public void useSmsCode(SmsCodeUseReqDTO reqDTO) { public void useSmsCode(SmsCodeUseReqDTO reqDTO) {
// 检测验证码是否有效 // 检测验证码是否有效
SmsCodeDO lastSmsCode = this.checkSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene()); SmsCodeDO lastSmsCode = validateSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene());
// 使用验证码 // 使用验证码
smsCodeMapper.updateById(SmsCodeDO.builder().id(lastSmsCode.getId()) smsCodeMapper.updateById(SmsCodeDO.builder().id(lastSmsCode.getId())
.used(true).usedTime(LocalDateTime.now()).usedIp(reqDTO.getUsedIp()).build()); .used(true).usedTime(LocalDateTime.now()).usedIp(reqDTO.getUsedIp()).build());
} }
@Override @Override
public void checkSmsCode(SmsCodeCheckReqDTO reqDTO) { public void validateSmsCode(SmsCodeValidateReqDTO reqDTO) {
checkSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene()); validateSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene());
} }
public SmsCodeDO checkSmsCode0(String mobile, String code, Integer scene) { private SmsCodeDO validateSmsCode0(String mobile, String code, Integer scene) {
// 校验验证码 // 校验验证码
SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, code, scene); SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, code, scene);
// 若验证码不存在抛出异常 // 若验证码不存在抛出异常
if (lastSmsCode == null) { if (lastSmsCode == null) {
throw ServiceExceptionUtil.exception(SMS_CODE_NOT_FOUND); throw exception(SMS_CODE_NOT_FOUND);
} }
// 超过时间 // 超过时间
if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis() if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis()
>= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期 >= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期
throw ServiceExceptionUtil.exception(SMS_CODE_EXPIRED); throw exception(SMS_CODE_EXPIRED);
} }
// 判断验证码是否已被使用 // 判断验证码是否已被使用
if (Boolean.TRUE.equals(lastSmsCode.getUsed())) { if (Boolean.TRUE.equals(lastSmsCode.getUsed())) {
throw ServiceExceptionUtil.exception(SMS_CODE_USED); throw exception(SMS_CODE_USED);
} }
return lastSmsCode; return lastSmsCode;
} }

View File

@ -15,7 +15,6 @@ 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.List;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
@ -118,8 +117,8 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
// 调用 // 调用
smsChannelService.deleteSmsChannel(id); smsChannelService.deleteSmsChannel(id);
// 校验数据不存在了 // 校验数据不存在了
assertNull(smsChannelMapper.selectById(id)); assertNull(smsChannelMapper.selectById(id));
// 校验调用 // 校验调用
verify(smsProducer, times(1)).sendSmsChannelRefreshMessage(); verify(smsProducer, times(1)).sendSmsChannelRefreshMessage();
} }
@ -178,31 +177,31 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
@Test @Test
public void testGetSmsChannelPage() { public void testGetSmsChannelPage() {
// mock 数据 // mock 数据
SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到 SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到
o.setSignature("芋道源码"); o.setSignature("芋道源码");
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(buildTime(2020, 12, 12)); o.setCreateTime(buildTime(2020, 12, 12));
}); });
smsChannelMapper.insert(dbSmsChannel); smsChannelMapper.insert(dbSmsChannel);
// 测试 signature 不匹配 // 测试 signature 不匹配
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码"))); smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码")));
// 测试 status 不匹配 // 测试 status 不匹配
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11)))); smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
// 准备参数 // 准备参数
SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO(); SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO();
reqVO.setSignature("芋道"); reqVO.setSignature("芋道");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24)); reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24));
// 调用 // 调用
PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO); PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO);
// 断言 // 断言
assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size()); assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbSmsChannel, pageResult.getList().get(0)); assertPojoEquals(dbSmsChannel, pageResult.getList().get(0));
} }
} }

View File

@ -0,0 +1,209 @@
package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO;
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.system.framework.sms.SmsCodeProperties;
import com.baomidou.mybatisplus.annotation.DbType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import static cn.hutool.core.util.RandomUtil.randomEle;
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.randomPojo;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@Import(SmsCodeServiceImpl.class)
public class SmsCodeServiceImplTest extends BaseDbUnitTest {
@Resource
private SmsCodeServiceImpl smsCodeService;
@Resource
private SmsCodeMapper smsCodeMapper;
@MockBean
private SmsCodeProperties smsCodeProperties;
@MockBean
private SmsSendService smsSendService;
@BeforeEach
public void setUp() {
when(smsCodeProperties.getExpireTimes()).thenReturn(Duration.ofMinutes(5));
when(smsCodeProperties.getSendFrequency()).thenReturn(Duration.ofMinutes(1));
when(smsCodeProperties.getSendMaximumQuantityPerDay()).thenReturn(10);
when(smsCodeProperties.getBeginCode()).thenReturn(9999);
when(smsCodeProperties.getEndCode()).thenReturn(9999);
}
@Test
public void sendSmsCode_success() {
// 准备参数
SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> {
o.setMobile("15601691300");
o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene());
});
// mock 方法
SqlConstants.init(DbType.MYSQL);
// 调用
smsCodeService.sendSmsCode(reqDTO);
// 断言 code 验证码
SmsCodeDO smsCodeDO = smsCodeMapper.selectOne(null);
assertPojoEquals(reqDTO, smsCodeDO);
assertEquals("9999", smsCodeDO.getCode());
assertEquals(1, smsCodeDO.getTodayIndex());
assertFalse(smsCodeDO.getUsed());
// 断言调用
verify(smsSendService).sendSingleSms(eq(reqDTO.getMobile()), isNull(), isNull(),
eq("user-sms-login"), eq(MapUtil.of("code", "9999")));
}
@Test
public void sendSmsCode_tooFast() {
// mock 数据
SmsCodeDO smsCodeDO = randomPojo(SmsCodeDO.class,
o -> o.setMobile("15601691300").setTodayIndex(1));
smsCodeMapper.insert(smsCodeDO);
// 准备参数
SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> {
o.setMobile("15601691300");
o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene());
});
// mock 方法
SqlConstants.init(DbType.MYSQL);
// 调用并断言异常
assertServiceException(() -> smsCodeService.sendSmsCode(reqDTO),
SMS_CODE_SEND_TOO_FAST);
}
@Test
public void sendSmsCode_exceedDay() {
// mock 数据
SmsCodeDO smsCodeDO = randomPojo(SmsCodeDO.class,
o -> o.setMobile("15601691300").setTodayIndex(10).setCreateTime(LocalDateTime.now()));
smsCodeMapper.insert(smsCodeDO);
// 准备参数
SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> {
o.setMobile("15601691300");
o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene());
});
// mock 方法
SqlConstants.init(DbType.MYSQL);
when(smsCodeProperties.getSendFrequency()).thenReturn(Duration.ofMillis(0));
// 调用并断言异常
assertServiceException(() -> smsCodeService.sendSmsCode(reqDTO),
SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
}
@Test
public void testUseSmsCode_success() {
// 准备参数
SmsCodeUseReqDTO reqDTO = randomPojo(SmsCodeUseReqDTO.class, o -> {
o.setMobile("15601691300");
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
});
// mock 数据
SqlConstants.init(DbType.MYSQL);
smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> {
o.setMobile(reqDTO.getMobile()).setScene(reqDTO.getScene())
.setCode(reqDTO.getCode()).setUsed(false);
}));
// 调用
smsCodeService.useSmsCode(reqDTO);
// 断言
SmsCodeDO smsCodeDO = smsCodeMapper.selectOne(null);
assertTrue(smsCodeDO.getUsed());
assertNotNull(smsCodeDO.getUsedTime());
assertEquals(reqDTO.getUsedIp(), smsCodeDO.getUsedIp());
}
@Test
public void validateSmsCode_success() {
// 准备参数
SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> {
o.setMobile("15601691300");
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
});
// mock 数据
SqlConstants.init(DbType.MYSQL);
smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile())
.setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(false)));
// 调用
smsCodeService.validateSmsCode(reqDTO);
}
@Test
public void validateSmsCode_notFound() {
// 准备参数
SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> {
o.setMobile("15601691300");
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
});
// mock 数据
SqlConstants.init(DbType.MYSQL);
// 调用并断言异常
assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO),
SMS_CODE_NOT_FOUND);
}
@Test
public void validateSmsCode_expired() {
// 准备参数
SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> {
o.setMobile("15601691300");
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
});
// mock 数据
SqlConstants.init(DbType.MYSQL);
smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile())
.setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(false)
.setCreateTime(LocalDateTime.now().minusMinutes(6))));
// 调用并断言异常
assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO),
SMS_CODE_EXPIRED);
}
@Test
public void validateSmsCode_used() {
// 准备参数
SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> {
o.setMobile("15601691300");
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
});
// mock 数据
SqlConstants.init(DbType.MYSQL);
smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile())
.setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(true)
.setCreateTime(LocalDateTime.now())));
// 调用并断言异常
assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO),
SMS_CODE_USED);
}
}

View File

@ -34,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
@Import(SmsLogServiceImpl.class) @Import(SmsLogServiceImpl.class)
public class SmsLogServiceTest extends BaseDbUnitTest { public class SmsLogServiceImplTest extends BaseDbUnitTest {
@Resource @Resource
private SmsLogServiceImpl smsLogService; private SmsLogServiceImpl smsLogService;
@ -44,47 +44,47 @@ public class SmsLogServiceTest extends BaseDbUnitTest {
@Test @Test
public void testGetSmsLogPage() { public void testGetSmsLogPage() {
// mock 数据 // mock 数据
SmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到 SmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到
o.setChannelId(1L); o.setChannelId(1L);
o.setTemplateId(10L); o.setTemplateId(10L);
o.setMobile("15601691300"); o.setMobile("15601691300");
o.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); o.setSendStatus(SmsSendStatusEnum.INIT.getStatus());
o.setSendTime(buildTime(2020, 11, 11)); o.setSendTime(buildTime(2020, 11, 11));
o.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); o.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
o.setReceiveTime(buildTime(2021, 11, 11)); o.setReceiveTime(buildTime(2021, 11, 11));
}); });
smsLogMapper.insert(dbSmsLog); smsLogMapper.insert(dbSmsLog);
// 测试 channelId 不匹配 // 测试 channelId 不匹配
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L))); smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L)));
// 测试 templateId 不匹配 // 测试 templateId 不匹配
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L))); smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L)));
// 测试 mobile 不匹配 // 测试 mobile 不匹配
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999"))); smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999")));
// 测试 sendStatus 不匹配 // 测试 sendStatus 不匹配
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SmsSendStatusEnum.IGNORE.getStatus()))); smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SmsSendStatusEnum.IGNORE.getStatus())));
// 测试 sendTime 不匹配 // 测试 sendTime 不匹配
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12)))); smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
// 测试 receiveStatus 不匹配 // 测试 receiveStatus 不匹配
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SmsReceiveStatusEnum.SUCCESS.getStatus()))); smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SmsReceiveStatusEnum.SUCCESS.getStatus())));
// 测试 receiveTime 不匹配 // 测试 receiveTime 不匹配
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12)))); smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
// 准备参数 // 准备参数
SmsLogPageReqVO reqVO = new SmsLogPageReqVO(); SmsLogPageReqVO reqVO = new SmsLogPageReqVO();
reqVO.setChannelId(1L); reqVO.setChannelId(1L);
reqVO.setTemplateId(10L); reqVO.setTemplateId(10L);
reqVO.setMobile("156"); reqVO.setMobile("156");
reqVO.setSendStatus(SmsSendStatusEnum.INIT.getStatus()); reqVO.setSendStatus(SmsSendStatusEnum.INIT.getStatus());
reqVO.setSendTime(buildBetweenTime(2020, 11, 1, 2020, 11, 30)); reqVO.setSendTime(buildBetweenTime(2020, 11, 1, 2020, 11, 30));
reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
reqVO.setReceiveTime(buildBetweenTime(2021, 11, 1, 2021, 11, 30)); reqVO.setReceiveTime(buildBetweenTime(2021, 11, 1, 2021, 11, 30));
// 调用 // 调用
PageResult<SmsLogDO> pageResult = smsLogService.getSmsLogPage(reqVO); PageResult<SmsLogDO> pageResult = smsLogService.getSmsLogPage(reqVO);
// 断言 // 断言
assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size()); assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbSmsLog, pageResult.getList().get(0)); assertPojoEquals(dbSmsLog, pageResult.getList().get(0));
} }
@Test @Test
@ -124,11 +124,11 @@ public class SmsLogServiceTest extends BaseDbUnitTest {
reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus()); reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
reqVO.setReceiveTime(buildBetweenTime(2021, 11, 1, 2021, 11, 30)); reqVO.setReceiveTime(buildBetweenTime(2021, 11, 1, 2021, 11, 30));
// 调用 // 调用
List<SmsLogDO> list = smsLogService.getSmsLogList(reqVO); List<SmsLogDO> list = smsLogService.getSmsLogList(reqVO);
// 断言 // 断言
assertEquals(1, list.size()); assertEquals(1, list.size());
assertPojoEquals(dbSmsLog, list.get(0)); assertPojoEquals(dbSmsLog, list.get(0));
} }
@Test @Test

View File

@ -1,288 +0,0 @@
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 SmsSendServiceTest 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 adminUserService 的方法
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())));
}
}

View File

@ -1,14 +1,5 @@
package cn.iocoder.yudao.module.system.service.sms; package cn.iocoder.yudao.module.system.service.sms;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO;
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.mysql.sms.SmsTemplateMapper;
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -19,6 +10,15 @@ 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.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO;
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.mysql.sms.SmsTemplateMapper;
import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum;
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
@ -30,20 +30,18 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import static cn.hutool.core.bean.BeanUtil.getFieldValue;
import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 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.AssertUtils.assertServiceException;
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 org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@Import(SmsTemplateServiceImpl.class) @Import(SmsTemplateServiceImpl.class)
public class SmsTemplateServiceTest extends BaseDbUnitTest { public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
@Resource @Resource
private SmsTemplateServiceImpl smsTemplateService; private SmsTemplateServiceImpl smsTemplateService;
@ -176,8 +174,8 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
// 调用 // 调用
smsTemplateService.deleteSmsTemplate(id); smsTemplateService.deleteSmsTemplate(id);
// 校验数据不存在了 // 校验数据不存在了
assertNull(smsTemplateMapper.selectById(id)); assertNull(smsTemplateMapper.selectById(id));
// 校验调用 // 校验调用
verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage(); verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage();
} }
@ -193,47 +191,47 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
@Test @Test
public void testGetSmsTemplatePage() { public void testGetSmsTemplatePage() {
// mock 数据 // mock 数据
SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到 SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到
o.setType(SmsTemplateTypeEnum.PROMOTION.getType()); o.setType(SmsTemplateTypeEnum.PROMOTION.getType());
o.setStatus(CommonStatusEnum.ENABLE.getStatus()); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCode("tudou"); o.setCode("tudou");
o.setContent("芋道源码"); o.setContent("芋道源码");
o.setApiTemplateId("yunai"); o.setApiTemplateId("yunai");
o.setChannelId(1L); o.setChannelId(1L);
o.setCreateTime(buildTime(2021, 11, 11)); o.setCreateTime(buildTime(2021, 11, 11));
}); });
smsTemplateMapper.insert(dbSmsTemplate); smsTemplateMapper.insert(dbSmsTemplate);
// 测试 type 不匹配 // 测试 type 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType()))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType())));
// 测试 status 不匹配 // 测试 status 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 code 不匹配 // 测试 code 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma"))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma")));
// 测试 content 不匹配 // 测试 content 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码"))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码")));
// 测试 apiTemplateId 不匹配 // 测试 apiTemplateId 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai"))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai")));
// 测试 channelId 不匹配 // 测试 channelId 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12)))); smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
// 准备参数 // 准备参数
SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO(); SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO();
reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType()); reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType());
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setCode("tu"); reqVO.setCode("tu");
reqVO.setContent("芋道"); reqVO.setContent("芋道");
reqVO.setApiTemplateId("yu"); reqVO.setApiTemplateId("yu");
reqVO.setChannelId(1L); reqVO.setChannelId(1L);
reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)})); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)}));
// 调用 // 调用
PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(reqVO); PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(reqVO);
// 断言 // 断言
assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size()); assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0)); assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0));
} }
@Test @Test
@ -273,11 +271,11 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
reqVO.setChannelId(1L); reqVO.setChannelId(1L);
reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)})); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)}));
// 调用 // 调用
List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateList(reqVO); List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateList(reqVO);
// 断言 // 断言
assertEquals(1, list.size()); assertEquals(1, list.size());
assertPojoEquals(dbSmsTemplate, list.get(0)); assertPojoEquals(dbSmsTemplate, list.get(0));
} }
@Test @Test

View File

@ -14,6 +14,7 @@ DELETE FROM "system_users";
DELETE FROM "system_sms_channel"; DELETE FROM "system_sms_channel";
DELETE FROM "system_sms_template"; DELETE FROM "system_sms_template";
DELETE FROM "system_sms_log"; DELETE FROM "system_sms_log";
DELETE FROM "system_sms_code";
DELETE FROM "system_error_code"; DELETE FROM "system_error_code";
DELETE FROM "system_social_user"; DELETE FROM "system_social_user";
DELETE FROM "system_social_user_bind"; DELETE FROM "system_social_user_bind";

View File

@ -377,6 +377,24 @@ CREATE TABLE IF NOT EXISTS "system_sms_log" (
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT '短信日志'; ) COMMENT '短信日志';
CREATE TABLE IF NOT EXISTS "system_sms_code" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"mobile" varchar(11) NOT NULL,
"code" varchar(11) NOT NULL,
"scene" bigint NOT NULL,
"create_ip" varchar NOT NULL,
"today_index" int NOT NULL,
"used" bit NOT NULL DEFAULT FALSE,
"used_time" timestamp DEFAULT NULL,
"used_ip" varchar NULL,
"creator" varchar(64) DEFAULT '',
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar(64) DEFAULT '',
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id")
) COMMENT '短信日志';
CREATE TABLE IF NOT EXISTS "system_error_code" ( CREATE TABLE IF NOT EXISTS "system_error_code" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"type" tinyint NOT NULL DEFAULT '0', "type" tinyint NOT NULL DEFAULT '0',
@ -568,19 +586,19 @@ CREATE TABLE IF NOT EXISTS "system_oauth2_code" (
) COMMENT 'OAuth2 刷新令牌'; ) COMMENT 'OAuth2 刷新令牌';
CREATE TABLE IF NOT EXISTS "system_mail_account" ( CREATE TABLE IF NOT EXISTS "system_mail_account" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"mail" varchar NOT NULL, "mail" varchar NOT NULL,
"username" varchar NOT NULL, "username" varchar NOT NULL,
"password" varchar NOT NULL, "password" varchar NOT NULL,
"host" varchar NOT NULL, "host" varchar NOT NULL,
"port" int NOT NULL, "port" int NOT NULL,
"ssl_enable" bit NOT NULL, "ssl_enable" bit NOT NULL,
"creator" varchar DEFAULT '', "creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '', "updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE, "deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT '邮箱账号表'; ) COMMENT '邮箱账号表';
CREATE TABLE IF NOT EXISTS "system_mail_template" ( CREATE TABLE IF NOT EXISTS "system_mail_template" (
@ -603,28 +621,28 @@ CREATE TABLE IF NOT EXISTS "system_mail_template" (
) COMMENT '邮件模版表'; ) COMMENT '邮件模版表';
CREATE TABLE IF NOT EXISTS "system_mail_log" ( CREATE TABLE IF NOT EXISTS "system_mail_log" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint, "user_id" bigint,
"user_type" varchar, "user_type" varchar,
"to_mail" varchar NOT NULL, "to_mail" varchar NOT NULL,
"account_id" bigint NOT NULL, "account_id" bigint NOT NULL,
"from_mail" varchar NOT NULL, "from_mail" varchar NOT NULL,
"template_id" bigint NOT NULL, "template_id" bigint NOT NULL,
"template_code" varchar NOT NULL, "template_code" varchar NOT NULL,
"template_nickname" varchar, "template_nickname" varchar,
"template_title" varchar NOT NULL, "template_title" varchar NOT NULL,
"template_content" varchar NOT NULL, "template_content" varchar NOT NULL,
"template_params" varchar NOT NULL, "template_params" varchar NOT NULL,
"send_status" varchar NOT NULL, "send_status" varchar NOT NULL,
"send_time" datetime, "send_time" datetime,
"send_message_id" varchar, "send_message_id" varchar,
"send_exception" varchar, "send_exception" varchar,
"creator" varchar DEFAULT '', "creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '', "updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE, "deleted" bit NOT NULL DEFAULT FALSE,
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT '邮件日志表'; ) COMMENT '邮件日志表';
-- 将该建表 SQL 语句,添加到 yudao-module-system-biz 模块的 test/resources/sql/create_tables.sql 文件里 -- 将该建表 SQL 语句,添加到 yudao-module-system-biz 模块的 test/resources/sql/create_tables.sql 文件里