初始化提交

This commit is contained in:
YangJ
2024-03-20 09:42:17 +08:00
commit 72f30209cf
3705 changed files with 285827 additions and 0 deletions

View File

@ -0,0 +1,98 @@
package cn.iocoder.yudao.module.member.service.address;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO;
import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO;
import cn.iocoder.yudao.module.member.dal.mysql.address.MemberAddressMapper;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
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.member.enums.ErrorCodeConstants.ADDRESS_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
/**
* {@link AddressServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(AddressServiceImpl.class)
public class MemberAddressServiceImplTest extends BaseDbUnitTest {
@Resource
private AddressServiceImpl addressService;
@Resource
private MemberAddressMapper addressMapper;
@Test
public void testCreateAddress_success() {
// 准备参数
AppAddressCreateReqVO reqVO = randomPojo(AppAddressCreateReqVO.class);
// 调用
Long addressId = addressService.createAddress(randomLongId(), reqVO);
// 断言
assertNotNull(addressId);
// 校验记录的属性是否正确
MemberAddressDO address = addressMapper.selectById(addressId);
assertPojoEquals(reqVO, address);
}
@Test
public void testUpdateAddress_success() {
// mock 数据
MemberAddressDO dbAddress = randomPojo(MemberAddressDO.class);
addressMapper.insert(dbAddress);// @Sql: 先插入出一条存在的数据
// 准备参数
AppAddressUpdateReqVO reqVO = randomPojo(AppAddressUpdateReqVO.class, o -> {
o.setId(dbAddress.getId()); // 设置更新的 ID
});
// 调用
addressService.updateAddress(dbAddress.getUserId(), reqVO);
// 校验是否更新正确
MemberAddressDO address = addressMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, address);
}
@Test
public void testUpdateAddress_notExists() {
// 准备参数
AppAddressUpdateReqVO reqVO = randomPojo(AppAddressUpdateReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> addressService.updateAddress(randomLongId(), reqVO), ADDRESS_NOT_EXISTS);
}
@Test
public void testDeleteAddress_success() {
// mock 数据
MemberAddressDO dbAddress = randomPojo(MemberAddressDO.class);
addressMapper.insert(dbAddress);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbAddress.getId();
// 调用
addressService.deleteAddress(dbAddress.getUserId(), id);
// 校验数据不存在了
assertNull(addressMapper.selectById(id));
}
@Test
public void testDeleteAddress_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> addressService.deleteAddress(randomLongId(), id), ADDRESS_NOT_EXISTS);
}
}

View File

@ -0,0 +1,118 @@
package cn.iocoder.yudao.module.member.service.auth;
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.framework.test.core.ut.BaseDbAndRedisUnitTest;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.system.api.logger.LoginLogApi;
import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;
import java.util.function.Consumer;
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;
// TODO @芋艿:单测的 review等逻辑都达成一致后
/**
* {@link MemberAuthService} 的单元测试类
*
* @author 宋天
*/
@Import({MemberAuthServiceImpl.class, YudaoRedisAutoConfiguration.class})
public class MemberAuthServiceTest extends BaseDbAndRedisUnitTest {
// TODO @芋艿:登录相关的单测,待补全
@Resource
private MemberAuthServiceImpl authService;
@MockBean
private MemberUserService userService;
@MockBean
private SmsCodeApi smsCodeApi;
@MockBean
private LoginLogApi loginLogApi;
@MockBean
private OAuth2TokenApi oauth2TokenApi;
@MockBean
private SocialUserApi socialUserApi;
@MockBean
private PasswordEncoder passwordEncoder;
@Resource
private MemberUserMapper memberUserMapper;
// TODO 芋艿:后续重构这个单测
// @Test
// public void testUpdatePassword_success(){
// // 准备参数
// MemberUserDO userDO = randomUserDO();
// memberUserMapper.insert(userDO);
//
// // 新密码
// String newPassword = randomString();
//
// // 请求实体
// AppMemberUserUpdatePasswordReqVO reqVO = AppMemberUserUpdatePasswordReqVO.builder()
// .oldPassword(userDO.getPassword())
// .password(newPassword)
// .build();
//
// // 测试桩
// // 这两个相等是为了返回ture这个结果
// when(passwordEncoder.matches(reqVO.getOldPassword(),reqVO.getOldPassword())).thenReturn(true);
// when(passwordEncoder.encode(newPassword)).thenReturn(newPassword);
//
// // 更新用户密码
// authService.updatePassword(userDO.getId(), reqVO);
// assertEquals(memberUserMapper.selectById(userDO.getId()).getPassword(),newPassword);
// }
// TODO 芋艿:后续重构这个单测
// @Test
// public void testResetPassword_success(){
// // 准备参数
// MemberUserDO userDO = randomUserDO();
// memberUserMapper.insert(userDO);
//
// // 随机密码
// String password = randomNumbers(11);
// // 随机验证码
// String code = randomNumbers(4);
//
// // mock
// when(passwordEncoder.encode(password)).thenReturn(password);
//
// // 更新用户密码
// AppMemberUserResetPasswordReqVO reqVO = new AppMemberUserResetPasswordReqVO();
// reqVO.setMobile(userDO.getMobile());
// reqVO.setPassword(password);
// reqVO.setCode(code);
//
// authService.resetPassword(reqVO);
// assertEquals(memberUserMapper.selectById(userDO.getId()).getPassword(),password);
// }
// ========== 随机对象 ==========
@SafeVarargs
private static MemberUserDO randomUserDO(Consumer<MemberUserDO>... consumers) {
Consumer<MemberUserDO> consumer = (o) -> {
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
o.setPassword(randomString());
};
return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers));
}
}

View File

@ -0,0 +1,160 @@
package cn.iocoder.yudao.module.member.service.group;
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.member.controller.admin.group.vo.MemberGroupCreateReqVO;
import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.group.vo.MemberGroupUpdateReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO;
import cn.iocoder.yudao.module.member.dal.mysql.group.MemberGroupMapper;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
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 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.*;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_HAS_USER;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.GROUP_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
// TODO 芋艿:完全 review 完,在去 review 单测
/**
* {@link MemberGroupServiceImpl} 的单元测试类
*
* @author owen
*/
@Import(MemberGroupServiceImpl.class)
public class MemberGroupServiceImplTest extends BaseDbUnitTest {
@Resource
private MemberGroupServiceImpl groupService;
@Resource
private MemberGroupMapper groupMapper;
@MockBean
private MemberUserService memberUserService;
@Test
public void testCreateGroup_success() {
// 准备参数
MemberGroupCreateReqVO reqVO = randomPojo(MemberGroupCreateReqVO.class,
o -> o.setStatus(randomCommonStatus()));
// 调用
Long groupId = groupService.createGroup(reqVO);
// 断言
assertNotNull(groupId);
// 校验记录的属性是否正确
MemberGroupDO group = groupMapper.selectById(groupId);
assertPojoEquals(reqVO, group);
}
@Test
public void testUpdateGroup_success() {
// mock 数据
MemberGroupDO dbGroup = randomPojo(MemberGroupDO.class);
groupMapper.insert(dbGroup);// @Sql: 先插入出一条存在的数据
// 准备参数
MemberGroupUpdateReqVO reqVO = randomPojo(MemberGroupUpdateReqVO.class, o -> {
o.setId(dbGroup.getId()); // 设置更新的 ID
o.setStatus(randomCommonStatus());
});
// 调用
groupService.updateGroup(reqVO);
// 校验是否更新正确
MemberGroupDO group = groupMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, group);
}
@Test
public void testUpdateGroup_notExists() {
// 准备参数
MemberGroupUpdateReqVO reqVO = randomPojo(MemberGroupUpdateReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> groupService.updateGroup(reqVO), GROUP_NOT_EXISTS);
}
@Test
public void testDeleteGroup_success() {
// mock 数据
MemberGroupDO dbGroup = randomPojo(MemberGroupDO.class);
groupMapper.insert(dbGroup);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbGroup.getId();
// 调用
groupService.deleteGroup(id);
// 校验数据不存在了
assertNull(groupMapper.selectById(id));
}
@Test
public void testDeleteGroup_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> groupService.deleteGroup(id), GROUP_NOT_EXISTS);
}
@Test
public void testDeleteGroup_hasUser() {
// mock 数据
MemberGroupDO dbGroup = randomPojo(MemberGroupDO.class);
groupMapper.insert(dbGroup);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbGroup.getId();
// mock 会员数据
when(memberUserService.getUserCountByGroupId(eq(id))).thenReturn(1L);
// 调用, 并断言异常
assertServiceException(() -> groupService.deleteGroup(id), GROUP_HAS_USER);
}
@Test
public void testGetGroupPage() {
String name = randomString();
int status = CommonStatusEnum.ENABLE.getStatus();
// mock 数据
MemberGroupDO dbGroup = randomPojo(MemberGroupDO.class, o -> { // 等会查询到
o.setName(name);
o.setStatus(status);
o.setCreateTime(buildTime(2023, 2, 18));
});
groupMapper.insert(dbGroup);
// 测试 name 不匹配
groupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setName("")));
// 测试 status 不匹配
groupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 createTime 不匹配
groupMapper.insert(cloneIgnoreId(dbGroup, o -> o.setCreateTime(null)));
// 准备参数
MemberGroupPageReqVO reqVO = new MemberGroupPageReqVO();
reqVO.setName(name);
reqVO.setStatus(status);
reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
// 调用
PageResult<MemberGroupDO> pageResult = groupService.getGroupPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbGroup, pageResult.getList().get(0));
}
}

View File

@ -0,0 +1,268 @@
package cn.iocoder.yudao.module.member.service.level;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelCreateReqVO;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelListReqVO;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.level.MemberLevelUpdateReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelMapper;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
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.util.List;
import java.util.function.Consumer;
import static cn.hutool.core.util.RandomUtil.randomInt;
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.*;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
import static org.junit.jupiter.api.Assertions.*;
// TODO 芋艿:完全 review 完,在去 review 单测
/**
* {@link MemberLevelServiceImpl} 的单元测试类
*
* @author owen
*/
@Import(MemberLevelServiceImpl.class)
public class MemberLevelServiceImplTest extends BaseDbUnitTest {
@Resource
private MemberLevelServiceImpl levelService;
@Resource
private MemberLevelMapper memberlevelMapper;
@MockBean
private MemberLevelRecordService memberLevelRecordService;
@MockBean
private MemberExperienceRecordService memberExperienceRecordService;
@MockBean
private MemberUserService memberUserService;
@Test
public void testCreateLevel_success() {
// 准备参数
MemberLevelCreateReqVO reqVO = randomPojo(MemberLevelCreateReqVO.class, o -> {
o.setDiscountPercent(randomInt());
o.setIcon(randomURL());
o.setBackgroundUrl(randomURL());
o.setStatus(randomCommonStatus());
});
// 调用
Long levelId = levelService.createLevel(reqVO);
// 断言
assertNotNull(levelId);
// 校验记录的属性是否正确
MemberLevelDO level = memberlevelMapper.selectById(levelId);
assertPojoEquals(reqVO, level);
}
@Test
public void testUpdateLevel_success() {
// mock 数据
MemberLevelDO dbLevel = randomPojo(MemberLevelDO.class);
memberlevelMapper.insert(dbLevel);// @Sql: 先插入出一条存在的数据
// 准备参数
MemberLevelUpdateReqVO reqVO = randomPojo(MemberLevelUpdateReqVO.class, o -> {
o.setId(dbLevel.getId()); // 设置更新的 ID
//以下要保持一致
o.setName(dbLevel.getName());
o.setLevel(dbLevel.getLevel());
o.setExperience(dbLevel.getExperience());
//以下是要修改的字段
o.setDiscountPercent(randomInt());
o.setIcon(randomURL());
o.setBackgroundUrl(randomURL());
o.setStatus(randomCommonStatus());
});
// 调用
levelService.updateLevel(reqVO);
// 校验是否更新正确
MemberLevelDO level = memberlevelMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, level);
}
@Test
public void testUpdateLevel_notExists() {
// 准备参数
MemberLevelUpdateReqVO reqVO = randomPojo(MemberLevelUpdateReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> levelService.updateLevel(reqVO), LEVEL_NOT_EXISTS);
}
@Test
public void testDeleteLevel_success() {
// mock 数据
MemberLevelDO dbLevel = randomPojo(MemberLevelDO.class);
memberlevelMapper.insert(dbLevel);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbLevel.getId();
// 调用
levelService.deleteLevel(id);
// 校验数据不存在了
assertNull(memberlevelMapper.selectById(id));
}
@Test
public void testDeleteLevel_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> levelService.deleteLevel(id), LEVEL_NOT_EXISTS);
}
@Test
public void testGetLevelList() {
// mock 数据
MemberLevelDO dbLevel = randomPojo(MemberLevelDO.class, o -> { // 等会查询到
o.setName("黄金会员");
o.setStatus(1);
});
memberlevelMapper.insert(dbLevel);
// 测试 name 不匹配
memberlevelMapper.insert(cloneIgnoreId(dbLevel, o -> o.setName("")));
// 测试 status 不匹配
memberlevelMapper.insert(cloneIgnoreId(dbLevel, o -> o.setStatus(0)));
// 准备参数
MemberLevelListReqVO reqVO = new MemberLevelListReqVO();
reqVO.setName("黄金会员");
reqVO.setStatus(1);
// 调用
List<MemberLevelDO> list = levelService.getLevelList(reqVO);
// 断言
assertEquals(1, list.size());
assertPojoEquals(dbLevel, list.get(0));
}
@Test
public void testCreateLevel_nameUnique() {
// 准备参数
String name = randomString();
// mock 数据
memberlevelMapper.insert(randomLevelDO(o -> o.setName(name)));
// 调用,校验异常
List<MemberLevelDO> list = memberlevelMapper.selectList();
assertServiceException(() -> levelService.validateNameUnique(list, null, name), LEVEL_NAME_EXISTS, name);
}
@Test
public void testUpdateLevel_nameUnique() {
// 准备参数
Long id = randomLongId();
String name = randomString();
// mock 数据
memberlevelMapper.insert(randomLevelDO(o -> o.setName(name)));
// 调用,校验异常
List<MemberLevelDO> list = memberlevelMapper.selectList();
assertServiceException(() -> levelService.validateNameUnique(list, id, name), LEVEL_NAME_EXISTS, name);
}
@Test
public void testCreateLevel_levelUnique() {
// 准备参数
Integer level = randomInteger();
String name = randomString();
// mock 数据
memberlevelMapper.insert(randomLevelDO(o -> {
o.setLevel(level);
o.setName(name);
}));
// 调用,校验异常
List<MemberLevelDO> list = memberlevelMapper.selectList();
assertServiceException(() -> levelService.validateLevelUnique(list, null, level), LEVEL_VALUE_EXISTS, level, name);
}
@Test
public void testUpdateLevel_levelUnique() {
// 准备参数
Long id = randomLongId();
Integer level = randomInteger();
String name = randomString();
// mock 数据
memberlevelMapper.insert(randomLevelDO(o -> {
o.setLevel(level);
o.setName(name);
}));
// 调用,校验异常
List<MemberLevelDO> list = memberlevelMapper.selectList();
assertServiceException(() -> levelService.validateLevelUnique(list, id, level), LEVEL_VALUE_EXISTS, level, name);
}
@Test
public void testCreateLevel_experienceOutRange() {
// 准备参数
int level = 10;
int experience = 10;
String name = randomString();
// mock 数据
memberlevelMapper.insert(randomLevelDO(o -> {
o.setLevel(level);
o.setExperience(experience);
o.setName(name);
}));
List<MemberLevelDO> list = memberlevelMapper.selectList();
// 调用,校验异常
assertServiceException(() -> levelService.validateExperienceOutRange(list, null, level + 1, experience - 1), LEVEL_EXPERIENCE_MIN, name, level);
// 调用,校验异常
assertServiceException(() -> levelService.validateExperienceOutRange(list, null, level - 1, experience + 1), LEVEL_EXPERIENCE_MAX, name, level);
}
@Test
public void testUpdateLevel_experienceOutRange() {
// 准备参数
int level = 10;
int experience = 10;
Long id = randomLongId();
String name = randomString();
// mock 数据
memberlevelMapper.insert(randomLevelDO(o -> {
o.setLevel(level);
o.setExperience(experience);
o.setName(name);
}));
List<MemberLevelDO> list = memberlevelMapper.selectList();
// 调用,校验异常
assertServiceException(() -> levelService.validateExperienceOutRange(list, id, level + 1, experience - 1), LEVEL_EXPERIENCE_MIN, name, level);
// 调用,校验异常
assertServiceException(() -> levelService.validateExperienceOutRange(list, id, level - 1, experience + 1), LEVEL_EXPERIENCE_MAX, name, level);
}
// ========== 随机对象 ==========
@SafeVarargs
private static MemberLevelDO randomLevelDO(Consumer<MemberLevelDO>... consumers) {
Consumer<MemberLevelDO> consumer = (o) -> {
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setDiscountPercent(randomInt(0, 100));
o.setIcon(randomURL());
o.setBackgroundUrl(randomURL());
};
return randomPojo(MemberLevelDO.class, ArrayUtils.append(consumer, consumers));
}
}

View File

@ -0,0 +1,133 @@
package cn.iocoder.yudao.module.member.service.tag;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagCreateReqVO;
import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.tag.vo.MemberTagUpdateReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
import cn.iocoder.yudao.module.member.dal.mysql.tag.MemberTagMapper;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
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 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.member.enums.ErrorCodeConstants.TAG_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*;
// TODO 芋艿:完全 review 完,在去 review 单测
/**
* {@link MemberTagServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(MemberTagServiceImpl.class)
public class MemberTagServiceImplTest extends BaseDbUnitTest {
@Resource
private MemberTagServiceImpl tagService;
@Resource
private MemberTagMapper tagMapper;
@MockBean
private MemberUserService memberUserService;
@Test
public void testCreateTag_success() {
// 准备参数
MemberTagCreateReqVO reqVO = randomPojo(MemberTagCreateReqVO.class);
// 调用
Long tagId = tagService.createTag(reqVO);
// 断言
assertNotNull(tagId);
// 校验记录的属性是否正确
MemberTagDO tag = tagMapper.selectById(tagId);
assertPojoEquals(reqVO, tag);
}
@Test
public void testUpdateTag_success() {
// mock 数据
MemberTagDO dbTag = randomPojo(MemberTagDO.class);
tagMapper.insert(dbTag);// @Sql: 先插入出一条存在的数据
// 准备参数
MemberTagUpdateReqVO reqVO = randomPojo(MemberTagUpdateReqVO.class, o -> {
o.setId(dbTag.getId()); // 设置更新的 ID
});
// 调用
tagService.updateTag(reqVO);
// 校验是否更新正确
MemberTagDO tag = tagMapper.selectById(reqVO.getId()); // 获取最新的
assertPojoEquals(reqVO, tag);
}
@Test
public void testUpdateTag_notExists() {
// 准备参数
MemberTagUpdateReqVO reqVO = randomPojo(MemberTagUpdateReqVO.class);
// 调用, 并断言异常
assertServiceException(() -> tagService.updateTag(reqVO), TAG_NOT_EXISTS);
}
@Test
public void testDeleteTag_success() {
// mock 数据
MemberTagDO dbTag = randomPojo(MemberTagDO.class);
tagMapper.insert(dbTag);// @Sql: 先插入出一条存在的数据
// 准备参数
Long id = dbTag.getId();
// 调用
tagService.deleteTag(id);
// 校验数据不存在了
assertNull(tagMapper.selectById(id));
}
@Test
public void testDeleteTag_notExists() {
// 准备参数
Long id = randomLongId();
// 调用, 并断言异常
assertServiceException(() -> tagService.deleteTag(id), TAG_NOT_EXISTS);
}
@Test
public void testGetTagPage() {
// mock 数据
MemberTagDO dbTag = randomPojo(MemberTagDO.class, o -> { // 等会查询到
o.setName("test");
o.setCreateTime(buildTime(2023, 2, 18));
});
tagMapper.insert(dbTag);
// 测试 name 不匹配
tagMapper.insert(cloneIgnoreId(dbTag, o -> o.setName("ne")));
// 测试 createTime 不匹配
tagMapper.insert(cloneIgnoreId(dbTag, o -> o.setCreateTime(null)));
// 准备参数
MemberTagPageReqVO reqVO = new MemberTagPageReqVO();
reqVO.setName("test");
reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
// 调用
PageResult<MemberTagDO> pageResult = tagService.getTagPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbTag, pageResult.getList().get(0));
}
}

View File

@ -0,0 +1,137 @@
package cn.iocoder.yudao.module.member.service.user;
import cn.hutool.core.util.RandomUtil;
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.framework.test.core.ut.BaseDbAndRedisUnitTest;
import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserUpdateMobileReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import org.junit.jupiter.api.Disabled;
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.crypto.password.PasswordEncoder;
import javax.annotation.Resource;
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.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;
// TODO @芋艿:单测的 review等逻辑都达成一致后
/**
* {@link MemberUserServiceImpl} 的单元测试类
*
* @author 宋天
*/
@Disabled
@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource
private MemberUserServiceImpl memberUserService;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private MemberUserMapper userMapper;
@MockBean
private MemberAuthServiceImpl authService;
@MockBean
private PasswordEncoder passwordEncoder;
@MockBean
private SmsCodeApi smsCodeApi;
@MockBean
private FileApi fileApi;
// TODO 芋艿:后续重构这个单测
// @Test
// public void testUpdateNickName_success(){
// // mock 数据
// MemberUserDO userDO = randomUserDO();
// userMapper.insert(userDO);
//
// // 随机昵称
// String newNickName = randomString();
//
// // 调用接口修改昵称
// memberUserService.updateUser(userDO.getId(),newNickName);
// // 查询新修改后的昵称
// String nickname = memberUserService.getUser(userDO.getId()).getNickname();
// // 断言
// assertEquals(newNickName,nickname);
// }
//
// @Test
// public void testUpdateAvatar_success() throws Exception {
// // mock 数据
// MemberUserDO dbUser = randomUserDO();
// userMapper.insert(dbUser);
//
// // 准备参数
// Long userId = dbUser.getId();
// byte[] avatarFileBytes = randomBytes(10);
// ByteArrayInputStream avatarFile = new ByteArrayInputStream(avatarFileBytes);
// // mock 方法
// String avatar = randomString();
// when(fileApi.createFile(eq(avatarFileBytes))).thenReturn(avatar);
// // 调用
// String str = memberUserService.updateUserAvatar(userId, avatarFile);
// // 断言
// assertEquals(avatar, str);
// }
@Test
@Disabled // TODO 芋艿:后续再修复
public void updateMobile_success(){
// mock数据
String oldMobile = randomNumbers(11);
MemberUserDO userDO = randomUserDO();
userDO.setMobile(oldMobile);
userMapper.insert(userDO);
// TODO 芋艿:需要修复该单元测试,重构多模块带来的
// 旧手机和旧验证码
// SmsCodeDO codeDO = new SmsCodeDO();
String oldCode = RandomUtil.randomString(4);
// codeDO.setMobile(userDO.getMobile());
// codeDO.setCode(oldCode);
// codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene());
// codeDO.setUsed(Boolean.FALSE);
// when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
// 更新手机号
String newMobile = randomNumbers(11);
String newCode = randomNumbers(4);
AppMemberUserUpdateMobileReqVO reqVO = new AppMemberUserUpdateMobileReqVO();
reqVO.setMobile(newMobile);
reqVO.setCode(newCode);
reqVO.setOldCode(oldCode);
memberUserService.updateUserMobile(userDO.getId(),reqVO);
assertEquals(memberUserService.getUser(userDO.getId()).getMobile(),newMobile);
}
// ========== 随机对象 ==========
@SafeVarargs
private static MemberUserDO randomUserDO(Consumer<MemberUserDO>... consumers) {
Consumer<MemberUserDO> consumer = (o) -> {
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
};
return randomPojo(MemberUserDO.class, ArrayUtils.append(consumer, consumers));
}
}

View File

@ -0,0 +1,49 @@
spring:
main:
lazy-initialization: true # 开启懒加载,加快速度
banner-mode: off # 单元测试,禁用 Banner
--- #################### 数据库相关配置 ####################
spring:
# 数据源配置项
datasource:
name: ruoyi-vue-pro
url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式DATABASE_TO_UPPER 配置表和字段使用小写
driver-class-name: org.h2.Driver
username: sa
password:
druid:
async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
initial-size: 1 # 单元测试,配置为 1提升启动速度
sql:
init:
schema-locations: classpath:/sql/create_tables.sql
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis:
host: 127.0.0.1 # 地址
port: 16379 # 端口(单元测试,使用 16379 端口)
database: 0 # 数据库索引
mybatis:
lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
--- #################### 定时任务相关配置 ####################
--- #################### 配置中心相关配置 ####################
--- #################### 服务保障相关配置 ####################
# Lock4j 配置项(单元测试,禁用 Lock4j
# Resilience4j 配置项
--- #################### 监控相关配置 ####################
--- #################### 芋道相关配置 ####################
# 芋道配置项,设置当前项目所有自定义的配置
yudao:
info:
base-package: cn.iocoder.yudao.module

View File

@ -0,0 +1,4 @@
<configuration>
<!-- 引用 Spring Boot 的 logback 基础配置 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
</configuration>

View File

@ -0,0 +1,5 @@
DELETE FROM "member_user";
DELETE FROM "member_address";
DELETE FROM "member_tag";
DELETE FROM "member_level";
DELETE FROM "member_group";

View File

@ -0,0 +1,113 @@
CREATE TABLE IF NOT EXISTS "member_user"
(
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号',
"nickname" varchar(30) NOT NULL DEFAULT '' COMMENT '用户昵称',
"name" varchar(30) NULL COMMENT '真实名字',
sex tinyint null comment '性别',
birthday datetime null comment '出生日期',
area_id int null comment '所在地',
mark varchar(255) null comment '用户备注',
point int default 0 null comment '积分',
"avatar" varchar(255) NOT NULL DEFAULT '' COMMENT '头像',
"status" tinyint NOT NULL COMMENT '状态',
"mobile" varchar(11) NOT NULL COMMENT '手机号',
"password" varchar(100) NOT NULL DEFAULT '' COMMENT '密码',
"register_ip" varchar(32) NOT NULL COMMENT '注册 IP',
"login_ip" varchar(50) NULL DEFAULT '' COMMENT '最后登录IP',
"login_date" datetime NULL DEFAULT NULL COMMENT '最后登录时间',
"tag_ids" varchar(255) NULL DEFAULT NULL COMMENT '用户标签编号列表,以逗号分隔',
"level_id" bigint NULL DEFAULT NULL COMMENT '等级编号',
"experience" bigint NULL DEFAULT NULL COMMENT '经验',
"group_id" bigint NULL DEFAULT NULL COMMENT '用户分组编号',
"creator" varchar(64) NULL DEFAULT '' COMMENT '创建者',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
"updater" varchar(64) NULL DEFAULT '' COMMENT '更新者',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
"deleted" bit(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '会员表';
CREATE TABLE IF NOT EXISTS "member_address" (
"id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint(20) NOT NULL,
"name" varchar(10) NOT NULL,
"mobile" varchar(20) NOT NULL,
"area_id" bigint(20) NOT NULL,
"detail_address" varchar(250) NOT NULL,
"default_status" bit NOT NULL,
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"creator" varchar(64) DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"updater" varchar(64) DEFAULT '',
PRIMARY KEY ("id")
) COMMENT '用户收件地址';
CREATE TABLE IF NOT EXISTS "member_tag"
(
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar NOT NULL,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint NOT NULL default '0',
PRIMARY KEY ("id")
) COMMENT '会员标签';
CREATE TABLE IF NOT EXISTS "member_level"
(
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar NOT NULL,
"experience" int NOT NULL,
"level" int NOT NULL,
"discount_percent" int NOT NULL,
"icon" varchar NOT NULL,
"background_url" varchar NOT NULL,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
"status" tinyint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
) COMMENT '会员等级';
CREATE TABLE IF NOT EXISTS "member_group"
(
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"name" varchar NOT NULL,
"remark" varchar NOT NULL,
"status" tinyint NOT NULL DEFAULT '0',
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '用户分组';
CREATE TABLE IF NOT EXISTS "member_brokerage_record"
(
"id" int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"user_id" bigint NOT NULL,
"biz_id" varchar NOT NULL,
"biz_type" varchar NOT NULL,
"title" varchar NOT NULL,
"price" int NOT NULL,
"total_price" int NOT NULL,
"description" varchar NOT NULL,
"status" varchar NOT NULL,
"frozen_days" int NOT NULL,
"unfreeze_time" varchar,
"creator" varchar DEFAULT '',
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updater" varchar DEFAULT '',
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"deleted" bit NOT NULL DEFAULT FALSE,
"tenant_id" bigint not null default '0',
PRIMARY KEY ("id")
) COMMENT '佣金记录';