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,6 +28,10 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
28 return selectOne(new QueryWrapper<T>().eq(field, value)); 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 default List<T> selectList() { 35 default List<T> selectList() {
32 return selectList(new QueryWrapper<>()); 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,13 +15,13 @@ import java.util.List;
15 @Mapper 15 @Mapper
16 public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> { 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 return selectOne(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType) 19 return selectOne(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType)
20 .eq("value", value)); 20 .eq("value", value));
21 } 21 }
22 22
23 default int selectCountByDictType(String dictType) { 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 default PageResult<SysDictDataDO> selectPage(SysDictDataPageReqVO reqVO) { 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,6 +15,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper;
15 import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer; 15 import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer;
16 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; 16 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
17 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService; 17 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
  18 +import com.google.common.annotations.VisibleForTesting;
18 import com.google.common.collect.ImmutableTable; 19 import com.google.common.collect.ImmutableTable;
19 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.scheduling.annotation.Scheduled; 21 import org.springframework.scheduling.annotation.Scheduled;
@@ -200,8 +201,9 @@ public class SysDictDataServiceImpl implements SysDictDataService { @@ -200,8 +201,9 @@ public class SysDictDataServiceImpl implements SysDictDataService {
200 checkDictDataValueUnique(id, dictType, value); 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 if (dictData == null) { 207 if (dictData == null) {
206 return; 208 return;
207 } 209 }
@@ -214,7 +216,8 @@ public class SysDictDataServiceImpl implements SysDictDataService { @@ -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 if (id == null) { 221 if (id == null) {
219 return; 222 return;
220 } 223 }
@@ -224,7 +227,8 @@ public class SysDictDataServiceImpl implements SysDictDataService { @@ -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 SysDictTypeDO dictType = dictTypeService.getDictType(type); 232 SysDictTypeDO dictType = dictTypeService.getDictType(type);
229 if (dictType == null) { 233 if (dictType == null) {
230 throw exception(DICT_TYPE_NOT_EXISTS); 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,6 +10,7 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
10 import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictTypeMapper; 10 import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictTypeMapper;
11 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; 11 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
12 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService; 12 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
  13 +import com.google.common.annotations.VisibleForTesting;
13 import org.springframework.stereotype.Service; 14 import org.springframework.stereotype.Service;
14 15
15 import javax.annotation.Resource; 16 import javax.annotation.Resource;
@@ -97,7 +98,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService { @@ -97,7 +98,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
97 checkDictTypeUnique(id, type); 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 SysDictTypeDO dictType = dictTypeMapper.selectByName(type); 103 SysDictTypeDO dictType = dictTypeMapper.selectByName(type);
102 if (dictType == null) { 104 if (dictType == null) {
103 return; 105 return;
@@ -111,7 +113,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService { @@ -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 SysDictTypeDO dictType = dictTypeMapper.selectByType(type); 118 SysDictTypeDO dictType = dictTypeMapper.selectByType(type);
116 if (dictType == null) { 119 if (dictType == null) {
117 return; 120 return;
@@ -125,7 +128,8 @@ public class SysDictTypeServiceImpl implements SysDictTypeService { @@ -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 if (id == null) { 133 if (id == null) {
130 return null; 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,6 +49,37 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
49 @MockBean 49 @MockBean
50 private SysDictDataProducer dictDataProducer; 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 @Test 83 @Test
53 public void testGetDictDataPage() { 84 public void testGetDictDataPage() {
54 // mock 数据 85 // mock 数据
@@ -126,46 +157,6 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest { @@ -126,46 +157,6 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
126 } 157 }
127 158
128 @Test 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 public void testUpdateDictData_success() { 160 public void testUpdateDictData_success() {
170 // mock 数据 161 // mock 数据
171 SysDictDataDO dbDictData = randomDictDataDO(); 162 SysDictDataDO dbDictData = randomDictDataDO();
@@ -188,123 +179,94 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest { @@ -188,123 +179,94 @@ public class SysDictDataServiceTest extends BaseSpringBootUnitTest {
188 } 179 }
189 180
190 @Test 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 @Test 197 @Test
203 - @SuppressWarnings("unchecked")  
204 - public void testInitLocalCache() { 198 + public void testCheckDictDataExists_success() {
205 // mock 数据 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 @Test 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 @Test 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 // mock 方法,数据类型被禁用 224 // mock 方法,数据类型被禁用
256 - when(dictTypeService.getDictType(eq(reqVO.getDictType()))).thenReturn( 225 + String dictType = randomString();
  226 + when(dictTypeService.getDictType(eq(dictType))).thenReturn(
257 randomPojo(SysDictTypeDO.class, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); 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 @Test 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 @Test 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 @Test 255 @Test
302 - public void testDeleteDictData_notExists() { 256 + public void testCheckDictDataValueUnique_valueDuplicateForUpdate() {
303 // 准备参数 257 // 准备参数
304 Long id = randomLongId(); 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 // ========== 随机对象 ==========