Commit 2249d76d46d7ece06067db2ca2f2a02b65289870

Authored by YunaiV
1 parent 351d08a2

简化 dict data 的单元测试,将新增、修改、删除涉及的公用方法,单独测试

src/main/java/cn/iocoder/dashboard/framework/mybatis/core/mapper/BaseMapperX.java
... ... @@ -28,6 +28,10 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
28 28 return selectOne(new QueryWrapper<T>().eq(field, value));
29 29 }
30 30  
  31 + default Integer selectCount(String field, Object value) {
  32 + return selectCount(new QueryWrapper<T>().eq(field, value));
  33 + }
  34 +
31 35 default List<T> selectList() {
32 36 return selectList(new QueryWrapper<>());
33 37 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java
... ... @@ -15,13 +15,13 @@ import java.util.List;
15 15 @Mapper
16 16 public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> {
17 17  
18   - default SysDictDataDO selectByDictTypeAndLabel(String dictType, String value) {
  18 + default SysDictDataDO selectByDictTypeAndValue(String dictType, String value) {
19 19 return selectOne(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType)
20 20 .eq("value", value));
21 21 }
22 22  
23 23 default int selectCountByDictType(String dictType) {
24   - return selectCount(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType));
  24 + return selectCount("dict_type", dictType);
25 25 }
26 26  
27 27 default PageResult<SysDictDataDO> selectPage(SysDictDataPageReqVO reqVO) {
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java
... ... @@ -15,6 +15,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
15 15 import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer;
16 16 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
17 17 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
  18 +import com.google.common.annotations.VisibleForTesting;
18 19 import com.google.common.collect.ImmutableTable;
19 20 import lombok.extern.slf4j.Slf4j;
20 21 import org.springframework.scheduling.annotation.Scheduled;
... ... @@ -200,8 +201,9 @@ public class SysDictDataServiceImpl implements SysDictDataService {
200 201 checkDictDataValueUnique(id, dictType, value);
201 202 }
202 203  
203   - private void checkDictDataValueUnique(Long id, String dictType, String label) {
204   - SysDictDataDO dictData = dictDataMapper.selectByDictTypeAndLabel(dictType, label);
  204 + @VisibleForTesting
  205 + public void checkDictDataValueUnique(Long id, String dictType, String value) {
  206 + SysDictDataDO dictData = dictDataMapper.selectByDictTypeAndValue(dictType, value);
205 207 if (dictData == null) {
206 208 return;
207 209 }
... ... @@ -214,7 +216,8 @@ public class SysDictDataServiceImpl implements SysDictDataService {
214 216 }
215 217 }
216 218  
217   - private void checkDictDataExists(Long id) {
  219 + @VisibleForTesting
  220 + public void checkDictDataExists(Long id) {
218 221 if (id == null) {
219 222 return;
220 223 }
... ... @@ -224,7 +227,8 @@ public class SysDictDataServiceImpl implements SysDictDataService {
224 227 }
225 228 }
226 229  
227   - private void checkDictTypeValid(String type) {
  230 + @VisibleForTesting
  231 + public void checkDictTypeValid(String type) {
228 232 SysDictTypeDO dictType = dictTypeService.getDictType(type);
229 233 if (dictType == null) {
230 234 throw exception(DICT_TYPE_NOT_EXISTS);
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictTypeServiceImpl.java
... ... @@ -10,6 +10,7 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
10 10 import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictTypeMapper;
11 11 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
12 12 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
  13 +import com.google.common.annotations.VisibleForTesting;
13 14 import org.springframework.stereotype.Service;
14 15  
15 16 import javax.annotation.Resource;
... ... @@ -97,7 +98,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
97 98 checkDictTypeUnique(id, type);
98 99 }
99 100  
100   - private void checkDictTypeNameUnique(Long id, String type) {
  101 + @VisibleForTesting
  102 + public void checkDictTypeNameUnique(Long id, String type) {
101 103 SysDictTypeDO dictType = dictTypeMapper.selectByName(type);
102 104 if (dictType == null) {
103 105 return;
... ... @@ -111,7 +113,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
111 113 }
112 114 }
113 115  
114   - private void checkDictTypeUnique(Long id, String type) {
  116 + @VisibleForTesting
  117 + public void checkDictTypeUnique(Long id, String type) {
115 118 SysDictTypeDO dictType = dictTypeMapper.selectByType(type);
116 119 if (dictType == null) {
117 120 return;
... ... @@ -125,7 +128,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
125 128 }
126 129 }
127 130  
128   - private SysDictTypeDO checkDictTypeExists(Long id) {
  131 + @VisibleForTesting
  132 + public SysDictTypeDO checkDictTypeExists(Long id) {
129 133 if (id == null) {
130 134 return null;
131 135 }
... ...
src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java
... ... @@ -49,6 +49,37 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
49 49 @MockBean
50 50 private SysDictDataProducer dictDataProducer;
51 51  
  52 + /**
  53 + * 测试加载到新的字典数据的情况
  54 + */
  55 + @Test
  56 + @SuppressWarnings("unchecked")
  57 + public void testInitLocalCache() {
  58 + // mock 数据
  59 + SysDictDataDO dictData01 = randomDictDataDO();
  60 + dictDataMapper.insert(dictData01);
  61 + SysDictDataDO dictData02 = randomDictDataDO();
  62 + dictDataMapper.insert(dictData02);
  63 +
  64 + // 调用
  65 + dictDataService.initLocalCache();
  66 + // 断言 labelDictDataCache 缓存
  67 + ImmutableTable<String, String, SysDictDataDO> labelDictDataCache =
  68 + (ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataService, "labelDictDataCache");
  69 + assertEquals(2, labelDictDataCache.size());
  70 + assertPojoEquals(dictData01, labelDictDataCache.get(dictData01.getDictType(), dictData01.getLabel()));
  71 + assertPojoEquals(dictData02, labelDictDataCache.get(dictData02.getDictType(), dictData02.getLabel()));
  72 + // 断言 valueDictDataCache 缓存
  73 + ImmutableTable<String, String, SysDictDataDO> valueDictDataCache =
  74 + (ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataService, "valueDictDataCache");
  75 + assertEquals(2, valueDictDataCache.size());
  76 + assertPojoEquals(dictData01, valueDictDataCache.get(dictData01.getDictType(), dictData01.getValue()));
  77 + assertPojoEquals(dictData02, valueDictDataCache.get(dictData02.getDictType(), dictData02.getValue()));
  78 + // 断言 maxUpdateTime 缓存
  79 + Date maxUpdateTime = (Date) getFieldValue(dictDataService, "maxUpdateTime");
  80 + assertEquals(ObjectUtils.max(dictData01.getUpdateTime(), dictData02.getUpdateTime()), maxUpdateTime);
  81 + }
  82 +
52 83 @Test
53 84 public void testGetDictDataPage() {
54 85 // mock 数据
... ... @@ -126,46 +157,6 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
126 157 }
127 158  
128 159 @Test
129   - public void testCreateDictData_dictTypeNotExists() {
130   - // 准备参数
131   - SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
132   - o -> o.setStatus(randomCommonStatus()));
133   -
134   - // 调用, 并断言异常
135   - assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_TYPE_NOT_EXISTS);
136   - }
137   -
138   - @Test
139   - public void testCreateDictData_dictTypeNotEnable() {
140   - // 准备参数
141   - SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
142   - o -> o.setStatus(randomCommonStatus()));
143   - // mock 方法,数据类型被禁用
144   - when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(
145   - randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
146   -
147   - // 调用, 并断言异常
148   - assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_TYPE_NOT_ENABLE);
149   - }
150   -
151   - @Test
152   - public void testCreateDictData_dictDataValueDuplicate() {
153   - // 准备参数
154   - SysDictDataCreateReqVO reqVO = randomPojo(SysDictDataCreateReqVO.class,
155   - o -> o.setStatus(randomCommonStatus()));
156   - // mock 方法,字典类型
157   - when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
158   - // mock dictData 重复 value 重复
159   - dictDataMapper.insert(randomDictDataDO(o -> {
160   - o.setDictType(reqVO.getDictType());
161   - o.setValue(reqVO.getValue()); // 使用 reqVO 的 value,实现重复
162   - }));
163   -
164   - // 调用, 并断言异常
165   - assertServiceException(() -> dictDataService.createDictData(reqVO), DICT_DATA_VALUE_DUPLICATE);
166   - }
167   -
168   - @Test
169 160 public void testUpdateDictData_success() {
170 161 // mock 数据
171 162 SysDictDataDO dbDictData = randomDictDataDO();
... ... @@ -188,123 +179,94 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
188 179 }
189 180  
190 181 @Test
191   - public void testUpdateDictData_notExists() {
  182 + public void testDeleteDictData_success() {
  183 + // mock 数据
  184 + SysDictDataDO dbDictData = randomDictDataDO();
  185 + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
192 186 // 准备参数
193   - SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class);
  187 + Long id = dbDictData.getId();
194 188  
195   - // 调用, 并断言异常
196   - assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_DATA_NOT_EXISTS);
  189 + // 调用
  190 + dictDataService.deleteDictData(id);
  191 + // 校验数据不存在了
  192 + assertNull(dictDataMapper.selectById(id));
  193 + // 校验调用
  194 + verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();
197 195 }
198 196  
199   - /**
200   - * 测试加载到新的字典数据的情况
201   - */
202 197 @Test
203   - @SuppressWarnings("unchecked")
204   - public void testInitLocalCache() {
  198 + public void testCheckDictDataExists_success() {
205 199 // mock 数据
206   - SysDictDataDO dictData01 = randomDictDataDO();
207   - dictDataMapper.insert(dictData01);
208   - SysDictDataDO dictData02 = randomDictDataDO();
209   - dictDataMapper.insert(dictData02);
  200 + SysDictDataDO dbDictData = randomDictDataDO();
  201 + dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
210 202  
211   - // 调用
212   - dictDataService.initLocalCache();
213   - // 断言 labelDictDataCache 缓存
214   - ImmutableTable<String, String, SysDictDataDO> labelDictDataCache =
215   - (ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataService, "labelDictDataCache");
216   - assertEquals(2, labelDictDataCache.size());
217   - assertPojoEquals(dictData01, labelDictDataCache.get(dictData01.getDictType(), dictData01.getLabel()));
218   - assertPojoEquals(dictData02, labelDictDataCache.get(dictData02.getDictType(), dictData02.getLabel()));
219   - // 断言 valueDictDataCache 缓存
220   - ImmutableTable<String, String, SysDictDataDO> valueDictDataCache =
221   - (ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataService, "valueDictDataCache");
222   - assertEquals(2, valueDictDataCache.size());
223   - assertPojoEquals(dictData01, valueDictDataCache.get(dictData01.getDictType(), dictData01.getValue()));
224   - assertPojoEquals(dictData02, valueDictDataCache.get(dictData02.getDictType(), dictData02.getValue()));
225   - // 断言 maxUpdateTime 缓存
226   - Date maxUpdateTime = (Date) getFieldValue(dictDataService, "maxUpdateTime");
227   - assertEquals(ObjectUtils.max(dictData01.getUpdateTime(), dictData02.getUpdateTime()), maxUpdateTime);
  203 + // 调用成功
  204 + dictDataService.checkDictDataExists(dbDictData.getId());
228 205 }
229 206  
230 207 @Test
231   - public void testUpdateDictData_dictTypeNotExists() {
232   - // mock 数据
233   - SysDictDataDO dbDictData = randomDictDataDO();
234   - dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
235   - // 准备参数
236   - SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
237   - o.setId(dbDictData.getId()); // 设置更新的 ID
238   - o.setStatus(randomCommonStatus());
239   - });
  208 + public void testCheckDictTypeValid_success() {
  209 + // mock 方法,数据类型被禁用
  210 + String type = randomString();
  211 + when(dictTypeService.getDictType(eq(type))).thenReturn(randomDictTypeDO(type));
240 212  
241   - // 调用, 并断言异常
242   - assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_TYPE_NOT_EXISTS);
  213 + // 调用, 成功
  214 + dictDataService.checkDictTypeValid(type);
243 215 }
244 216  
245 217 @Test
246   - public void testUpdateDictData_dictTypeNotEnable() {
247   - // mock 数据
248   - SysDictDataDO dbDictData = randomDictDataDO();
249   - dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
250   - // 准备参数
251   - SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
252   - o.setId(dbDictData.getId()); // 设置更新的 ID
253   - o.setStatus(randomCommonStatus());
254   - });
  218 + public void testCheckDictTypeValid_notExists() {
  219 + assertServiceException(() -> dictDataService.checkDictTypeValid(randomString()), DICT_TYPE_NOT_EXISTS);
  220 + }
  221 +
  222 + @Test
  223 + public void testCheckDictTypeValid_notEnable() {
255 224 // mock 方法,数据类型被禁用
256   - when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(
  225 + String dictType = randomString();
  226 + when(dictTypeService.getDictType(eq(dictType))).thenReturn(
257 227 randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
258 228  
259 229 // 调用, 并断言异常
260   - assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_TYPE_NOT_ENABLE);
  230 + assertServiceException(() -> dictDataService.checkDictTypeValid(dictType), DICT_TYPE_NOT_ENABLE);
261 231 }
262 232  
263 233 @Test
264   - public void testUpdateDictData_dictDataValueDuplicate() {
265   - // mock 数据
266   - SysDictDataDO dbDictData = randomDictDataDO();
267   - dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
268   - // 准备参数
269   - SysDictDataUpdateReqVO reqVO = randomPojo(SysDictDataUpdateReqVO.class, o -> {
270   - o.setId(dbDictData.getId()); // 设置更新的 ID
271   - o.setStatus(randomCommonStatus());
272   - });
273   - // mock 方法,字典类型
274   - when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn(randomDictTypeDO(reqVO.getDictType()));
275   - // mock dictData 重复 value 重复
276   - dictDataMapper.insert(randomDictDataDO(o -> {
277   - o.setDictType(reqVO.getDictType());
278   - o.setValue(reqVO.getValue()); // 使用 reqVO 的 value,实现重复
279   - }));
280   -
281   - // 调用, 并断言异常
282   - assertServiceException(() -> dictDataService.updateDictData(reqVO), DICT_DATA_VALUE_DUPLICATE);
  234 + public void testCheckDictDataValueUnique_success() {
  235 + // 调用,成功
  236 + dictDataService.checkDictDataValueUnique(randomLongId(), randomString(), randomString());
283 237 }
284 238  
285 239 @Test
286   - public void testDeleteDictData_success() {
287   - // mock 数据
288   - SysDictDataDO dbDictData = randomDictDataDO();
289   - dictDataMapper.insert(dbDictData);// @Sql: 先插入出一条存在的数据
  240 + public void testCheckDictDataValueUnique_valueDuplicateForCreate() {
290 241 // 准备参数
291   - Long id = dbDictData.getId();
  242 + String dictType = randomString();
  243 + String value = randomString();
  244 + // mock 数据
  245 + dictDataMapper.insert(randomDictDataDO(o -> {
  246 + o.setDictType(dictType);
  247 + o.setValue(value);
  248 + }));
292 249  
293   - // 调用
294   - dictDataService.deleteDictData(id);
295   - // 校验数据不存在了
296   - assertNull(dictDataMapper.selectById(id));
297   - // 校验调用
298   - verify(dictDataProducer, times(1)).sendDictDataRefreshMessage();
  250 + // 调用,校验异常
  251 + assertServiceException(() -> dictDataService.checkDictDataValueUnique(null, dictType, value),
  252 + DICT_DATA_VALUE_DUPLICATE);
299 253 }
300 254  
301 255 @Test
302   - public void testDeleteDictData_notExists() {
  256 + public void testCheckDictDataValueUnique_valueDuplicateForUpdate() {
303 257 // 准备参数
304 258 Long id = randomLongId();
  259 + String dictType = randomString();
  260 + String value = randomString();
  261 + // mock 数据
  262 + dictDataMapper.insert(randomDictDataDO(o -> {
  263 + o.setDictType(dictType);
  264 + o.setValue(value);
  265 + }));
305 266  
306   - // 调用, 并断言异常
307   - assertServiceException(() -> dictDataService.deleteDictData(id), DICT_DATA_NOT_EXISTS);
  267 + // 调用,校验异常
  268 + assertServiceException(() -> dictDataService.checkDictDataValueUnique(id, dictType, value),
  269 + DICT_DATA_VALUE_DUPLICATE);
308 270 }
309 271  
310 272 // ========== 随机对象 ==========
... ...