Commit e2b76ee0e5f4d9f5edc57c5f22d9dc736daf1fd0

Authored by YunaiV
1 parent 42ce5c75

code review 修改密码等的单元测试

yudao-admin-server/pom.xml
@@ -117,8 +117,6 @@ @@ -117,8 +117,6 @@
117 <artifactId>yudao-spring-boot-starter-excel</artifactId> 117 <artifactId>yudao-spring-boot-starter-excel</artifactId>
118 </dependency> 118 </dependency>
119 119
120 -  
121 -  
122 <dependency> 120 <dependency>
123 <groupId>org.apache.velocity</groupId> 121 <groupId>org.apache.velocity</groupId>
124 <artifactId>velocity-engine-core</artifactId> 122 <artifactId>velocity-engine-core</artifactId>
yudao-user-server/pom.xml
@@ -91,6 +91,7 @@ @@ -91,6 +91,7 @@
91 <scope>test</scope> 91 <scope>test</scope>
92 </dependency> 92 </dependency>
93 93
  94 + <!-- TODO @宋天:junit 已经在 yudao-spring-boot-starter-test 啦,不用在引入哈 -->
94 <!--单元测试相关--> 95 <!--单元测试相关-->
95 <dependency> 96 <dependency>
96 <groupId>junit</groupId> 97 <groupId>junit</groupId>
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java
@@ -70,6 +70,7 @@ public class SysUserProfileController { @@ -70,6 +70,7 @@ public class SysUserProfileController {
70 @PreAuthenticated 70 @PreAuthenticated
71 public CommonResult<Boolean> updateMobile(@RequestBody @Valid MbrUserUpdateMobileReqVO reqVO) { 71 public CommonResult<Boolean> updateMobile(@RequestBody @Valid MbrUserUpdateMobileReqVO reqVO) {
72 // 校验验证码 72 // 校验验证码
  73 + // TODO @宋天:统一到 userService.updateMobile 方法里
73 smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP()); 74 smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
74 75
75 userService.updateMobile(getLoginUserId(), reqVO); 76 userService.updateMobile(getLoginUserId(), reqVO);
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/vo/MbrUserUpdateMobileReqVO.java
@@ -25,9 +25,9 @@ public class MbrUserUpdateMobileReqVO { @@ -25,9 +25,9 @@ public class MbrUserUpdateMobileReqVO {
25 @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") 25 @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
26 private String code; 26 private String code;
27 27
28 -  
29 @ApiModelProperty(value = "手机号",required = true,example = "15823654487") 28 @ApiModelProperty(value = "手机号",required = true,example = "15823654487")
30 @NotBlank(message = "手机号不能为空") 29 @NotBlank(message = "手机号不能为空")
  30 + // TODO @宋天:手机校验,直接使用 @Mobile 哈
31 @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位") 31 @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位")
32 @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误") 32 @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误")
33 private String mobile; 33 private String mobile;
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java
@@ -126,8 +126,10 @@ public class MbrUserServiceImpl implements MbrUserService { @@ -126,8 +126,10 @@ public class MbrUserServiceImpl implements MbrUserService {
126 // 检测用户是否存在 126 // 检测用户是否存在
127 MbrUserDO userDO = checkUserExists(userId); 127 MbrUserDO userDO = checkUserExists(userId);
128 // 检测手机与验证码是否匹配 128 // 检测手机与验证码是否匹配
  129 + // TODO @宋天:修改手机的时候。应该要校验,老手机 + 老手机 code;新手机 + 新手机 code
129 sysAuthService.checkIfMobileMatchCodeAndDeleteCode(userDO.getMobile(),reqVO.getCode()); 130 sysAuthService.checkIfMobileMatchCodeAndDeleteCode(userDO.getMobile(),reqVO.getCode());
130 // 更新用户手机 131 // 更新用户手机
  132 + // TODO @宋天:更新的时候,单独创建对象。直接全量更新,会可能导致属性覆盖。可以看看打印出来的 SQL 哈
131 userDO.setMobile(reqVO.getMobile()); 133 userDO.setMobile(reqVO.getMobile());
132 userMapper.updateById(userDO); 134 userMapper.updateById(userDO);
133 } 135 }
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/SysAuthController.java
@@ -98,6 +98,7 @@ public class SysAuthController { @@ -98,6 +98,7 @@ public class SysAuthController {
98 @ApiOperation(value = "校验验证码是否正确") 98 @ApiOperation(value = "校验验证码是否正确")
99 @PreAuthenticated 99 @PreAuthenticated
100 public CommonResult<Boolean> checkSmsCode(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) { 100 public CommonResult<Boolean> checkSmsCode(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) {
  101 + // TODO @宋天:check 的时候,不应该使用 useSmsCode 哈,这样验证码就直接被使用了。另外,check 开头的方法,更多是校验的逻辑,不会有 update 数据的动作。这点,在方法命名上,也是要注意的
101 smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHECK_CODE_BY_SMS.getScene(),reqVO.getCode(),getClientIP()); 102 smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHECK_CODE_BY_SMS.getScene(),reqVO.getCode(),getClientIP());
102 return success(true); 103 return success(true);
103 } 104 }
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthResetPasswordReqVO.java
@@ -8,7 +8,6 @@ import lombok.Data; @@ -8,7 +8,6 @@ import lombok.Data;
8 import lombok.NoArgsConstructor; 8 import lombok.NoArgsConstructor;
9 import org.hibernate.validator.constraints.Length; 9 import org.hibernate.validator.constraints.Length;
10 10
11 -import javax.validation.constraints.NotBlank;  
12 import javax.validation.constraints.NotEmpty; 11 import javax.validation.constraints.NotEmpty;
13 import javax.validation.constraints.Pattern; 12 import javax.validation.constraints.Pattern;
14 13
@@ -29,4 +28,5 @@ public class MbrAuthResetPasswordReqVO { @@ -29,4 +28,5 @@ public class MbrAuthResetPasswordReqVO {
29 @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") 28 @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位")
30 @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") 29 @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
31 private String code; 30 private String code;
  31 +
32 } 32 }
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
@@ -285,6 +285,7 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -285,6 +285,7 @@ public class SysAuthServiceImpl implements SysAuthService {
285 MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword()); 285 MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
286 286
287 // 更新用户密码 287 // 更新用户密码
  288 + // TODO @宋天:不要更新整个对象哈
288 userDO.setPassword(passwordEncoder.encode(reqVO.getPassword())); 289 userDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
289 userMapper.updateById(userDO); 290 userMapper.updateById(userDO);
290 } 291 }
@@ -300,6 +301,8 @@ public class SysAuthServiceImpl implements SysAuthService { @@ -300,6 +301,8 @@ public class SysAuthServiceImpl implements SysAuthService {
300 // TODO @芋艿 这一步没必要检验验证码与手机是否匹配,因为是根据验证码去redis中查找手机号,然后根据手机号查询用户 301 // TODO @芋艿 这一步没必要检验验证码与手机是否匹配,因为是根据验证码去redis中查找手机号,然后根据手机号查询用户
301 // 也就是说 即便黑客以其他方式将验证码发送到自己手机上,最终还是会根据手机号查询用户然后进行重置密码的操作,不存在安全问题 302 // 也就是说 即便黑客以其他方式将验证码发送到自己手机上,最终还是会根据手机号查询用户然后进行重置密码的操作,不存在安全问题
302 303
  304 + // TODO @宋天:这块微信在讨论下哈~~~
  305 +
303 // 校验验证码 306 // 校验验证码
304 smsCodeService.useSmsCode(userDO.getMobile(), SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP()); 307 smsCodeService.useSmsCode(userDO.getMobile(), SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
305 308
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/sms/impl/SysSmsCodeServiceImpl.java
@@ -58,10 +58,14 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { @@ -58,10 +58,14 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
58 // 创建验证码 58 // 创建验证码
59 String code = this.createSmsCode(mobile, scene, createIp); 59 String code = this.createSmsCode(mobile, scene, createIp);
60 // 发送验证码 60 // 发送验证码
  61 + // TODO @宋天:这里可以拓展下 SysSmsSceneEnum,支持设置对应的短信模板编号(不同场景的短信文案是不同的)、是否要校验手机号已经注册。这样 Controller 就可以收口成一个接口了。相当于说,不同场景,不同策略
61 smsCoreService.sendSingleSmsToMember(mobile, null, SysSmsTemplateCodeConstants.USER_SMS_LOGIN, 62 smsCoreService.sendSingleSmsToMember(mobile, null, SysSmsTemplateCodeConstants.USER_SMS_LOGIN,
62 MapUtil.of("code", code)); 63 MapUtil.of("code", code));
63 64
64 // 存储手机号与验证码到redis,用于标记 65 // 存储手机号与验证码到redis,用于标记
  66 + // TODO @宋天:SysSmsCodeDO 表应该足够,无需增加额外的 redis 存储哇
  67 + // TODO @宋天:Redis 相关的操作,不要散落到业务层,而是写一个它对应的 RedisDAO。这样,实现业务与技术的解耦
  68 + // TODO @宋天:直接使用 code 作为 key,会存在 2 个问题:1)code 可能会冲突,多个手机号之间;2)缺少前缀。例如说 sms_code_${code}
65 stringRedisTemplate.opsForValue().set(code,mobile,CODE_TIME, TimeUnit.MINUTES); 69 stringRedisTemplate.opsForValue().set(code,mobile,CODE_TIME, TimeUnit.MINUTES);
66 } 70 }
67 71
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/member/controller/SysUserProfileControllerTest.java
@@ -22,6 +22,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @@ -22,6 +22,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
22 * 22 *
23 * @author 宋天 23 * @author 宋天
24 */ 24 */
  25 +// TODO @宋天:controller 的单测可以不写哈,因为收益太低了。未来我们做 qa 自动化测试
25 public class SysUserProfileControllerTest { 26 public class SysUserProfileControllerTest {
26 27
27 private MockMvc mockMvc; 28 private MockMvc mockMvc;
@@ -35,7 +36,7 @@ public class SysUserProfileControllerTest { @@ -35,7 +36,7 @@ public class SysUserProfileControllerTest {
35 @Mock 36 @Mock
36 private SysSmsCodeService smsCodeService; 37 private SysSmsCodeService smsCodeService;
37 38
38 - @Before 39 + @Before // TODO @宋天:使用 junit5 哈
39 public void setup() { 40 public void setup() {
40 // 初始化 41 // 初始化
41 MockitoAnnotations.openMocks(this); 42 MockitoAnnotations.openMocks(this);
@@ -52,7 +53,7 @@ public class SysUserProfileControllerTest { @@ -52,7 +53,7 @@ public class SysUserProfileControllerTest {
52 .content("{\"mobile\":\"15819844280\",\"code\":\"123456\"}}")) 53 .content("{\"mobile\":\"15819844280\",\"code\":\"123456\"}}"))
53 .andExpect(status().isOk()) 54 .andExpect(status().isOk())
54 .andDo(MockMvcResultHandlers.print()); 55 .andDo(MockMvcResultHandlers.print());
55 - 56 +// TODO @宋天:方法的结尾,不用空行哈
56 } 57 }
57 58
58 59
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/member/service/MbrUserServiceImplTest.java
@@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
7 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; 7 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
8 import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest; 8 import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest;
9 -import cn.iocoder.yudao.userserver.BaseDbUnitTest;  
10 import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; 9 import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
11 import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; 10 import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
12 import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; 11 import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
@@ -15,7 +14,6 @@ import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSend @@ -15,7 +14,6 @@ import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSend
15 import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; 14 import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
16 import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl; 15 import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl;
17 import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; 16 import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
18 -import cn.iocoder.yudao.userserver.modules.system.service.sms.impl.SysSmsCodeServiceImpl;  
19 import org.junit.jupiter.api.Test; 17 import org.junit.jupiter.api.Test;
20 import org.springframework.boot.test.mock.mockito.MockBean; 18 import org.springframework.boot.test.mock.mockito.MockBean;
21 import org.springframework.context.annotation.Import; 19 import org.springframework.context.annotation.Import;
@@ -23,14 +21,16 @@ import org.springframework.data.redis.core.StringRedisTemplate; @@ -23,14 +21,16 @@ import org.springframework.data.redis.core.StringRedisTemplate;
23 import org.springframework.security.crypto.password.PasswordEncoder; 21 import org.springframework.security.crypto.password.PasswordEncoder;
24 22
25 import javax.annotation.Resource; 23 import javax.annotation.Resource;
26 -import java.io.*; 24 +import java.io.ByteArrayInputStream;
27 import java.util.function.Consumer; 25 import java.util.function.Consumer;
28 26
29 import static cn.hutool.core.util.RandomUtil.*; 27 import static cn.hutool.core.util.RandomUtil.*;
30 -import static org.junit.jupiter.api.Assertions.assertEquals;  
31 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 28 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
32 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; 29 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
  30 +import static org.junit.jupiter.api.Assertions.assertEquals;
33 import static org.mockito.Mockito.*; 31 import static org.mockito.Mockito.*;
  32 +
  33 +// TODO @芋艿:单测的 review,等逻辑都达成一致后
34 /** 34 /**
35 * {@link MbrUserServiceImpl} 的单元测试类 35 * {@link MbrUserServiceImpl} 的单元测试类
36 * 36 *
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/system/service/SysAuthServiceTest.java
1 package cn.iocoder.yudao.userserver.modules.system.service; 1 package cn.iocoder.yudao.userserver.modules.system.service;
2 2
3 -import cn.hutool.core.util.ArrayUtil;  
4 import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; 3 import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
5 -import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;  
6 import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService; 4 import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
7 import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService; 5 import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
8 import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService; 6 import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
@@ -10,11 +8,8 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; @@ -10,11 +8,8 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
10 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; 8 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
11 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; 9 import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
12 import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest; 10 import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest;
13 -import cn.iocoder.yudao.userserver.BaseDbUnitTest;  
14 -import cn.iocoder.yudao.userserver.config.RedisTestConfiguration;  
15 import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; 11 import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
16 import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; 12 import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
17 -import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl;  
18 import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthResetPasswordReqVO; 13 import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthResetPasswordReqVO;
19 import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthUpdatePasswordReqVO; 14 import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthUpdatePasswordReqVO;
20 import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; 15 import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
@@ -28,17 +23,17 @@ import org.springframework.security.authentication.AuthenticationManager; @@ -28,17 +23,17 @@ import org.springframework.security.authentication.AuthenticationManager;
28 import org.springframework.security.crypto.password.PasswordEncoder; 23 import org.springframework.security.crypto.password.PasswordEncoder;
29 24
30 import javax.annotation.Resource; 25 import javax.annotation.Resource;
31 -  
32 import java.util.concurrent.TimeUnit; 26 import java.util.concurrent.TimeUnit;
33 import java.util.function.Consumer; 27 import java.util.function.Consumer;
34 28
35 import static cn.hutool.core.util.RandomUtil.randomEle; 29 import static cn.hutool.core.util.RandomUtil.randomEle;
36 import static cn.hutool.core.util.RandomUtil.randomNumbers; 30 import static cn.hutool.core.util.RandomUtil.randomNumbers;
37 -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; 31 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  32 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
38 import static org.junit.jupiter.api.Assertions.assertEquals; 33 import static org.junit.jupiter.api.Assertions.assertEquals;
39 -import static org.mockito.Mockito.*;  
40 - 34 +import static org.mockito.Mockito.when;
41 35
  36 +// TODO @芋艿:单测的 review,等逻辑都达成一致后
42 /** 37 /**
43 * {@link SysAuthService} 的单元测试类 38 * {@link SysAuthService} 的单元测试类
44 * 39 *
@@ -68,7 +63,6 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest { @@ -68,7 +63,6 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
68 @Resource 63 @Resource
69 private SysAuthServiceImpl authService; 64 private SysAuthServiceImpl authService;
70 65
71 -  
72 @Test 66 @Test
73 public void testUpdatePassword_success(){ 67 public void testUpdatePassword_success(){
74 // 准备参数 68 // 准备参数