update 新增接口:修改手机,修改密码,忘记密码

This commit is contained in:
宋天
2021-11-17 10:15:22 +08:00
parent c84e19e14e
commit 8e0569ee54
19 changed files with 696 additions and 18 deletions

View File

@@ -0,0 +1,48 @@
package cn.iocoder.yudao.userserver;
import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import cn.iocoder.yudao.userserver.config.RedisTestConfiguration;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
/**
* 依赖内存 DB + Redis 的单元测试
*
* 相比 {@link BaseDbUnitTest} 来说,额外增加了内存 Redis
*
* @author 芋道源码
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class)
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
public class BaseDbAndRedisUnitTest {
@Import({
// DB 配置类
YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
DruidDataSourceAutoConfigure.class, // Druid 自动配置类
// MyBatis 配置类
YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
// Redis 配置类
RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
RedisAutoConfiguration.class, // Spring Redis 自动配置类
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
RedissonAutoConfiguration.class, // Redisson 自动高配置类
})
public static class Application {
}
}

View File

@@ -0,0 +1,30 @@
package cn.iocoder.yudao.userserver.config;
import com.github.fppt.jedismock.RedisServer;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import java.io.IOException;
@Configuration(proxyBeanMethods = false)
@Lazy(false) // 禁止延迟加载
@EnableConfigurationProperties(RedisProperties.class)
public class RedisTestConfiguration {
/**
* 创建模拟的 Redis Server 服务器
*/
@Bean
public RedisServer redisServer(RedisProperties properties) throws IOException {
RedisServer redisServer = new RedisServer(properties.getPort());
// TODO 芋艿:一次执行多个单元测试时,貌似创建多个 spring 容器,导致不进行 stop。这样就导致端口被占用无法启动。。。
try {
redisServer.start();
} catch (Exception ignore) {}
return redisServer;
}
}

View File

@@ -0,0 +1,59 @@
package cn.iocoder.yudao.userserver.modules.member.controller;
import cn.iocoder.yudao.userserver.modules.member.controller.user.SysUserProfileController;
import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* {@link SysUserProfileController} 的单元测试类
*
* @author 宋天
*/
public class SysUserProfileControllerTest {
private MockMvc mockMvc;
@InjectMocks
private SysUserProfileController sysUserProfileController;
@Mock
private MbrUserService userService;
@Mock
private SysSmsCodeService smsCodeService;
@Before
public void setup() {
// 初始化
MockitoAnnotations.openMocks(this);
// 构建mvc环境
mockMvc = MockMvcBuilders.standaloneSetup(sysUserProfileController).build();
}
@Test
public void testUpdateMobile_success() throws Exception {
//模拟接口调用
this.mockMvc.perform(post("/system/user/profile/update-mobile")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content("{\"mobile\":\"15819844280\",\"code\":\"123456\"}}"))
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print());
}
}

View File

@@ -2,28 +2,32 @@ package cn.iocoder.yudao.userserver.modules.member.service;
import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService;
import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest;
import cn.iocoder.yudao.userserver.BaseDbUnitTest;
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl;
import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import cn.iocoder.yudao.userserver.modules.system.service.sms.impl.SysSmsCodeServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.io.*;
import java.util.function.Consumer;
import static cn.hutool.core.util.RandomUtil.randomBytes;
import static cn.hutool.core.util.RandomUtil.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.mockito.Mockito.*;
@@ -32,21 +36,30 @@ import static org.mockito.Mockito.*;
*
* @author 宋天
*/
@Import(MbrUserServiceImpl.class)
public class MbrUserServiceImplTest extends BaseDbUnitTest {
@Import({MbrUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource
private MbrUserServiceImpl mbrUserService;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private MbrUserMapper userMapper;
@MockBean
private SysAuthServiceImpl authService;
@MockBean
private InfFileCoreService fileCoreService;
@MockBean
private PasswordEncoder passwordEncoder;
@MockBean
private SysSmsCodeService sysSmsCodeService;
@Test
public void testUpdateNickName_success(){
// mock 数据
@@ -94,6 +107,37 @@ public class MbrUserServiceImplTest extends BaseDbUnitTest {
assertEquals(avatar, str);
}
@Test
public void updateMobile_success(){
// mock数据
String oldMobile = randomNumbers(11);
MbrUserDO userDO = randomMbrUserDO();
userDO.setMobile(oldMobile);
userMapper.insert(userDO);
// 验证旧手机
sysSmsCodeService.sendSmsCodeLogin(userDO.getId());
// 验证旧手机验证码是否正确
sysSmsCodeService.useSmsCode(oldMobile,SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(),"123","1.1.1.1");
// 验证新手机
SysAuthSendSmsReqVO smsReqVO = new SysAuthSendSmsReqVO();
smsReqVO.setMobile(oldMobile);
smsReqVO.setScene(SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene());
sysSmsCodeService.sendSmsNewCode(smsReqVO);
// 更新手机号
String newMobile = randomNumbers(11);
String code = randomNumbers(4);
MbrUserUpdateMobileReqVO reqVO = new MbrUserUpdateMobileReqVO();
reqVO.setMobile(newMobile);
reqVO.setCode(code);
mbrUserService.updateMobile(userDO.getId(),reqVO);
assertEquals(mbrUserService.getUser(userDO.getId()).getMobile(),newMobile);
}
// ========== 随机对象 ==========
@SafeVarargs

View File

@@ -0,0 +1,75 @@
package cn.iocoder.yudao.userserver.modules.system.controller;
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
import cn.iocoder.yudao.userserver.modules.system.controller.auth.SysAuthController;
import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.http.HttpHeaders.AUTHORIZATION;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* {@link SysAuthController} 的单元测试类
*
* @author 宋天
*/
public class SysAuthControllerTest {
private MockMvc mockMvc;
@InjectMocks
private SysAuthController sysAuthController;
@Mock
private SysAuthService authService;
@Mock
private SysSmsCodeService smsCodeService;
@Mock
private SysSocialService socialService;
@Before
public void setup() {
// 初始化
MockitoAnnotations.openMocks(this);
// 构建mvc环境
mockMvc = MockMvcBuilders.standaloneSetup(sysAuthController).build();
}
@Test
public void testResetPassword_success() throws Exception {
//模拟接口调用
this.mockMvc.perform(post("/reset-password")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"password\":\"1123\",\"code\":\"123456\"}}"))
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print());
}
@Test
public void testUpdatePassword_success() throws Exception {
//模拟接口调用
this.mockMvc.perform(post("/update-password")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"password\":\"1123\",\"code\":\"123456\",\"oldPassword\":\"1123\"}}"))
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print());
}
}

View File

@@ -0,0 +1,134 @@
package cn.iocoder.yudao.userserver.modules.system.service;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest;
import cn.iocoder.yudao.userserver.BaseDbUnitTest;
import cn.iocoder.yudao.userserver.config.RedisTestConfiguration;
import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl;
import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthResetPasswordReqVO;
import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.hutool.core.util.RandomUtil.randomNumbers;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
/**
* {@link SysAuthService} 的单元测试类
*
* @author 宋天
*/
@Import({SysAuthServiceImpl.class, YudaoRedisAutoConfiguration.class})
public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
@MockBean
private AuthenticationManager authenticationManager;
@MockBean
private MbrUserService userService;
@MockBean
private SysSmsCodeService smsCodeService;
@MockBean
private SysLoginLogCoreService loginLogCoreService;
@MockBean
private SysUserSessionCoreService userSessionCoreService;
@MockBean
private SysSocialService socialService;
@Resource
private StringRedisTemplate stringRedisTemplate;
@MockBean
private PasswordEncoder passwordEncoder;
@Resource
private MbrUserMapper mbrUserMapper;
@Resource
private SysAuthServiceImpl authService;
@Test
public void testUpdatePassword_success(){
// 准备参数
MbrUserDO userDO = randomMbrUserDO();
mbrUserMapper.insert(userDO);
// 新密码
String newPassword = randomString();
// 请求实体
MbrAuthResetPasswordReqVO reqVO = new MbrAuthResetPasswordReqVO();
reqVO.setOldPassword(userDO.getPassword());
reqVO.setPassword(newPassword);
// 测试桩
// 这两个相等是为了返回ture这个结果
when(passwordEncoder.matches(reqVO.getOldPassword(),reqVO.getOldPassword())).thenReturn(true);
when(passwordEncoder.encode(newPassword)).thenReturn(newPassword);
// 更新用户密码
authService.updatePassword(userDO.getId(),reqVO);
assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),newPassword);
}
@Test
public void testResetPassword_success(){
// 准备参数
MbrUserDO userDO = randomMbrUserDO();
mbrUserMapper.insert(userDO);
// 随机密码
String password = randomNumbers(11);
// 随机验证码
String code = randomNumbers(4);
MbrAuthResetPasswordReqVO reqVO = new MbrAuthResetPasswordReqVO();
reqVO.setPassword(password);
reqVO.setCode(code);
// 放入code+手机号
stringRedisTemplate.opsForValue().set(code,userDO.getMobile(),10, TimeUnit.MINUTES);
// mock
when(passwordEncoder.encode(password)).thenReturn(password);
// 更新用户密码
authService.resetPassword(reqVO);
assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),password);
}
// ========== 随机对象 ==========
@SafeVarargs
private static MbrUserDO randomMbrUserDO(Consumer<MbrUserDO>... consumers) {
Consumer<MbrUserDO> consumer = (o) -> {
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
o.setPassword(randomString());
};
return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers));
}
}