Commit 113e34b2791ec9b54f5c2cd915890057454d92ed

Authored by YunaiV
1 parent cafb72b5

完善 dict data 的单元测试

src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java
... ... @@ -15,9 +15,9 @@ import java.util.List;
15 15 @Mapper
16 16 public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> {
17 17  
18   - default SysDictDataDO selectByDictTypeAndLabel(String dictType, String label) {
  18 + default SysDictDataDO selectByDictTypeAndLabel(String dictType, String value) {
19 19 return selectOne(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType)
20   - .eq("label", label));
  20 + .eq("value", value));
21 21 }
22 22  
23 23 default int selectCountByDictType(String dictType) {
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.dict.impl;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
5   -import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
6 5 import cn.iocoder.dashboard.common.pojo.PageResult;
7 6 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
8 7 import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataCreateReqVO;
... ... @@ -10,9 +9,9 @@ import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataEx
10 9 import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataPageReqVO;
11 10 import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataUpdateReqVO;
12 11 import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert;
13   -import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
14 12 import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictDataDO;
15 13 import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
  14 +import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
16 15 import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer;
17 16 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
18 17 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
... ... @@ -28,6 +27,7 @@ import java.util.Comparator;
28 27 import java.util.Date;
29 28 import java.util.List;
30 29  
  30 +import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
31 31 import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
32 32  
33 33 /**
... ... @@ -156,7 +156,7 @@ public class SysDictDataServiceImpl implements SysDictDataService {
156 156 @Override
157 157 public Long createDictData(SysDictDataCreateReqVO reqVO) {
158 158 // 校验正确性
159   - this.checkCreateOrUpdate(null, reqVO.getLabel(), reqVO.getDictType());
  159 + this.checkCreateOrUpdate(null, reqVO.getValue(), reqVO.getDictType());
160 160 // 插入字典类型
161 161 SysDictDataDO dictData = SysDictDataConvert.INSTANCE.convert(reqVO);
162 162 dictDataMapper.insert(dictData);
... ... @@ -168,7 +168,7 @@ public class SysDictDataServiceImpl implements SysDictDataService {
168 168 @Override
169 169 public void updateDictData(SysDictDataUpdateReqVO reqVO) {
170 170 // 校验正确性
171   - this.checkCreateOrUpdate(reqVO.getId(), reqVO.getLabel(), reqVO.getDictType());
  171 + this.checkCreateOrUpdate(reqVO.getId(), reqVO.getValue(), reqVO.getDictType());
172 172 // 更新字典类型
173 173 SysDictDataDO updateObj = SysDictDataConvert.INSTANCE.convert(reqVO);
174 174 dictDataMapper.updateById(updateObj);
... ... @@ -191,13 +191,13 @@ public class SysDictDataServiceImpl implements SysDictDataService {
191 191 return dictDataMapper.selectCountByDictType(dictType);
192 192 }
193 193  
194   - private void checkCreateOrUpdate(Long id, String label, String dictType) {
  194 + private void checkCreateOrUpdate(Long id, String value, String dictType) {
195 195 // 校验自己存在
196 196 checkDictDataExists(id);
197 197 // 校验字典类型有效
198 198 checkDictTypeValid(dictType);
199 199 // 校验字典数据的值的唯一性
200   - checkDictDataValueUnique(id, dictType, label);
  200 + checkDictDataValueUnique(id, dictType, value);
201 201 }
202 202  
203 203 private void checkDictDataValueUnique(Long id, String dictType, String label) {
... ... @@ -207,10 +207,10 @@ public class SysDictDataServiceImpl implements SysDictDataService {
207 207 }
208 208 // 如果 id 为空,说明不用比较是否为相同 id 的字典数据
209 209 if (id == null) {
210   - throw ServiceExceptionUtil.exception(DICT_DATA_VALUE_DUPLICATE);
  210 + throw exception(DICT_DATA_VALUE_DUPLICATE);
211 211 }
212 212 if (!dictData.getId().equals(id)) {
213   - throw ServiceExceptionUtil.exception(DICT_DATA_VALUE_DUPLICATE);
  213 + throw exception(DICT_DATA_VALUE_DUPLICATE);
214 214 }
215 215 }
216 216  
... ... @@ -220,17 +220,17 @@ public class SysDictDataServiceImpl implements SysDictDataService {
220 220 }
221 221 SysDictDataDO dictData = dictDataMapper.selectById(id);
222 222 if (dictData == null) {
223   - throw ServiceExceptionUtil.exception(DICT_DATA_NOT_EXISTS);
  223 + throw exception(DICT_DATA_NOT_EXISTS);
224 224 }
225 225 }
226 226  
227 227 private void checkDictTypeValid(String type) {
228 228 SysDictTypeDO dictType = dictTypeService.getDictType(type);
229 229 if (dictType == null) {
230   - throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_EXISTS);
  230 + throw exception(DICT_TYPE_NOT_EXISTS);
231 231 }
232 232 if (!CommonStatusEnum.ENABLE.getStatus().equals(dictType.getStatus())) {
233   - throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_ENABLE);
  233 + throw exception(DICT_TYPE_NOT_ENABLE);
234 234 }
235 235 }
236 236  
... ...
src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java
... ... @@ -2,6 +2,8 @@ package cn.iocoder.dashboard.util.collection;
2 2  
3 3 import cn.hutool.core.util.ArrayUtil;
4 4  
  5 +import java.util.function.Consumer;
  6 +
5 7 /**
6 8 * Array 工具类
7 9 *
... ... @@ -18,11 +20,11 @@ public class ArrayUtils {
18 20 * @return 结果数组
19 21 */
20 22 @SafeVarargs
21   - public static <T> T[] append(T object, T... newElements) {
  23 + public static <T> Consumer<T>[] append(Consumer<T> object, Consumer<T>... newElements) {
22 24 if (object == null) {
23 25 return newElements;
24 26 }
25   - T[] result = ArrayUtil.newArray(object.getClass(), 1 + newElements.length);
  27 + Consumer<T>[] result = ArrayUtil.newArray(Consumer.class, 1 + newElements.length);
26 28 result[0] = object;
27 29 System.arraycopy(newElements, 0, result, 1, newElements.length);
28 30 return result;
... ...
src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java
... ... @@ -12,14 +12,16 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
12 12 import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
13 13 import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer;
14 14 import cn.iocoder.dashboard.modules.system.service.dict.impl.SysDictDataServiceImpl;
  15 +import cn.iocoder.dashboard.util.collection.ArrayUtils;
15 16 import cn.iocoder.dashboard.util.object.ObjectUtils;
16 17 import org.junit.jupiter.api.Test;
17 18 import org.springframework.boot.test.mock.mockito.MockBean;
18 19  
19 20 import javax.annotation.Resource;
20 21 import java.util.List;
  22 +import java.util.function.Consumer;
21 23  
22   -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.DICT_DATA_NOT_EXISTS;
  24 +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
23 25 import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
24 26 import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
25 27 import static cn.iocoder.dashboard.util.RandomUtils.*;
... ... @@ -107,8 +109,7 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
107 109 SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
108 110 o -> o.setStatus(randomCommonStatus()));
109 111 // mock 方法
110   - when(dictTypeService.getDictType(eq(reqVO.getDictType())))
111   - .thenReturn(randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus())));
  112 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
112 113  
113 114 // 调用
114 115 Long dictDataId = dictDataService.createDictData(reqVO);
... ... @@ -122,20 +123,65 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
122 123 }
123 124  
124 125 @Test
  126 + public void testCreateDictData_dictTypeNotExists() {
  127 + // 准备参数
  128 + SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
  129 + o -> o.setStatus(randomCommonStatus()));
  130 +
  131 + // 调用, 并断言异常
  132 + assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_TYPE_NOT_EXISTS);
  133 + }
  134 +
  135 + @Test
  136 + public void testCreateDictData_dictTypeNotEnable() {
  137 + // 准备参数
  138 + SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
  139 + o -> o.setStatus(randomCommonStatus()));
  140 + // mock 方法,数据类型被禁用
  141 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(
  142 + randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
  143 +
  144 + // 调用, 并断言异常
  145 + assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_TYPE_NOT_ENABLE);
  146 + }
  147 +
  148 + @Test
  149 + public void testCreateDictData_dictDataValueDuplicate() {
  150 + // 准备参数
  151 + SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
  152 + o -> o.setStatus(randomCommonStatus()));
  153 + // mock 方法,字典类型
  154 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
  155 + // mock dictData 重复 value 重复
  156 + dictDataMapper.insert(randomDictDataDO(o -> {
  157 + o.setDictType(reqVO.getDictType());
  158 + o.setValue(reqVO.getValue()); // 使用 reqVO 的 value,实现重复
  159 + }));
  160 +
  161 + // 调用, 并断言异常
  162 + assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_DATA_VALUE_DUPLICATE);
  163 + }
  164 +
  165 + @Test
125 166 public void testUpdateDictData_success() {
126 167 // mock 数据
127   - SysDictDataDO dbDictData = randomPojo(SysDictDataDO.class);
  168 + SysDictDataDO dbDictData = randomDictDataDO();
128 169 dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
129 170 // 准备参数
130 171 SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
131 172 o.setId(dbDictData.getId()); // 设置更新的 ID
  173 + o.setStatus(randomCommonStatus());
132 174 });
  175 + // mock 方法,字典类型
  176 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
133 177  
134 178 // 调用
135 179 dictDataService.updateDictData(reqVO);
136 180 // 校验是否更新正确
137 181 SysDictDataDO dictData = dictDataMapper.selectById(reqVO.getId()); // 获取最新的
138 182 assertPojoEquals(reqVO, dictData);
  183 + // 校验调用
  184 + verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();
139 185 }
140 186  
141 187 @Test
... ... @@ -148,17 +194,74 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
148 194 }
149 195  
150 196 @Test
  197 + public void testUpdateDictData_dictTypeNotExists() {
  198 + // mock 数据
  199 + SysDictDataDO dbDictData = randomDictDataDO();
  200 + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
  201 + // 准备参数
  202 + SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
  203 + o.setId(dbDictData.getId()); // 设置更新的 ID
  204 + o.setStatus(randomCommonStatus());
  205 + });
  206 +
  207 + // 调用, 并断言异常
  208 + assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_TYPE_NOT_EXISTS);
  209 + }
  210 +
  211 + @Test
  212 + public void testUpdateDictData_dictTypeNotEnable() {
  213 + // mock 数据
  214 + SysDictDataDO dbDictData = randomDictDataDO();
  215 + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
  216 + // 准备参数
  217 + SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
  218 + o.setId(dbDictData.getId()); // 设置更新的 ID
  219 + o.setStatus(randomCommonStatus());
  220 + });
  221 + // mock 方法,数据类型被禁用
  222 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(
  223 + randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
  224 +
  225 + // 调用, 并断言异常
  226 + assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_TYPE_NOT_ENABLE);
  227 + }
  228 +
  229 + @Test
  230 + public void testUpdateDictData_dictDataValueDuplicate() {
  231 + // mock 数据
  232 + SysDictDataDO dbDictData = randomDictDataDO();
  233 + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
  234 + // 准备参数
  235 + SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
  236 + o.setId(dbDictData.getId()); // 设置更新的 ID
  237 + o.setStatus(randomCommonStatus());
  238 + });
  239 + // mock 方法,字典类型
  240 + when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
  241 + // mock dictData 重复 value 重复
  242 + dictDataMapper.insert(randomDictDataDO(o -> {
  243 + o.setDictType(reqVO.getDictType());
  244 + o.setValue(reqVO.getValue()); // 使用 reqVO 的 value,实现重复
  245 + }));
  246 +
  247 + // 调用, 并断言异常
  248 + assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_DATA_VALUE_DUPLICATE);
  249 + }
  250 +
  251 + @Test
151 252 public void testDeleteDictData_success() {
152 253 // mock 数据
153   - SysDictDataDO dbDictData = randomPojo(SysDictDataDO.class);
  254 + SysDictDataDO dbDictData = randomDictDataDO();
154 255 dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
155 256 // 准备参数
156 257 Long id = dbDictData.getId();
157 258  
158 259 // 调用
159 260 dictDataService.deleteDictData(id);
160   - // 校验数据不存在了
161   - assertNull(dictDataMapper.selectById(id));
  261 + // 校验数据不存在了
  262 + assertNull(dictDataMapper.selectById(id));
  263 + // 校验调用
  264 + verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();
162 265 }
163 266  
164 267 @Test
... ... @@ -170,4 +273,27 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
170 273 assertServiceException(() -> dictDataService.deleteDictData(id), DICT_DATA_NOT_EXISTS);
171 274 }
172 275  
  276 + // ========== 随机对象 ==========
  277 +
  278 + @SafeVarargs
  279 + private static SysDictDataDO randomDictDataDO(Consumer<SysDictDataDO>... consumers) {
  280 + Consumer<SysDictDataDO> consumer = (o) -> {
  281 + o.setStatus(randomCommonStatus()); // 保证 status 的范围
  282 + };
  283 + return randomPojo(SysDictDataDO.class, ArrayUtils.append(consumer, consumers));
  284 + }
  285 +
  286 + /**
  287 + * 生成一个有效的字典类型
  288 + *
  289 + * @param type 字典类型
  290 + * @return SysDictTypeDO 对象
  291 + */
  292 + private static SysDictTypeDO randomDictTypeDO(String type) {
  293 + return randomPojo(SysDictTypeDO.class, o -> {
  294 + o.setType(type);
  295 + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 是开启
  296 + });
  297 + }
  298 +
173 299 }
... ...