Kaynağa Gözat

完成 dict type 的单元测试

YunaiV 4 yıl önce
ebeveyn
işleme
4120084cef
19 değiştirilmiş dosya ile 437 ekleme ve 2793 silme
  1. 27 25
      ruoyi-ui/src/views/system/dict/index.vue
  2. 47 2714
      sql/ruoyi-vue-pro.sql
  3. 4 4
      src/main/java/cn/iocoder/dashboard/framework/mybatis/core/mapper/BaseMapperX.java
  4. 3 3
      src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictTypeController.java
  5. 4 6
      src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/type/SysDictTypeExportReqVO.java
  6. 4 4
      src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/type/SysDictTypePageReqVO.java
  7. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/dict/SysDictTypeDO.java
  8. 8 7
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictTypeMapper.java
  9. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java
  10. 3 3
      src/main/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeService.java
  11. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java
  12. 11 11
      src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictTypeServiceImpl.java
  13. 31 0
      src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java
  14. 4 4
      src/main/resources/codegen/java/test/serviceTest.vm
  15. 10 8
      src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java
  16. 263 0
      src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java
  17. 0 1
      src/test/java/cn/iocoder/dashboard/modules/system/service/package-info.java
  18. 1 0
      src/test/resources/sql/clean.sql
  19. 14 0
      src/test/resources/sql/create_tables.sql

+ 27 - 25
ruoyi-ui/src/views/system/dict/index.vue

@@ -39,7 +39,7 @@
       </el-form-item>
       <el-form-item label="创建时间">
         <el-date-picker
-          v-model="dateRange"
+          v-model="dateRangeCreateTime"
           size="small"
           style="width: 240px"
           value-format="yyyy-MM-dd"
@@ -177,7 +177,7 @@ export default {
       // 状态数据字典
       statusOptions: [],
       // 日期范围
-      dateRange: [],
+      dateRangeCreateTime: [],
       // 查询参数
       queryParams: {
         pageNo: 1,
@@ -211,15 +211,15 @@ export default {
     /** 查询字典类型列表 */
     getList() {
       this.loading = true;
-      listType(this.addDateRange(this.queryParams, [
-        this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
-        this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
-      ])).then(response => {
-          this.typeList = response.data.list;
-          this.total = response.data.total;
-          this.loading = false;
-        }
-      );
+      // 处理查询参数
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行查询
+      listType(params).then(response => {
+        this.typeList = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
     },
     // 字典状态字典翻译
     statusFormat(row, column) {
@@ -248,7 +248,7 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
-      this.dateRange = [];
+      this.dateRangeCreateTime = [];
       this.resetForm("queryForm");
       this.handleQuery();
     },
@@ -304,19 +304,21 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.addDateRange(this.queryParams, [
-        this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
-        this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
-      ]);
-      this.$confirm('是否确认导出所有类型数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return exportType(queryParams);
-        }).then(response => {
-          this.downloadExcel(response, '数据类型.xls');
-        })
+      // 处理查询参数
+      let params = {...this.queryParams};
+      params.pageNo = undefined;
+      params.pageSize = undefined;
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行导出
+      this.$confirm('是否确认导出所有字典类型数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return exportType(params);
+      }).then(response => {
+        this.downloadExcel(response, '字典类型.xls');
+      })
     }
   }
 };

Dosya farkı çok büyük olduğundan ihmal edildi
+ 47 - 2714
sql/ruoyi-vue-pro.sql


+ 4 - 4
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/mapper/BaseMapperX.java

@@ -24,12 +24,12 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
         return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
     }
 
-    default List<T> selectList() {
-        return selectList(new QueryWrapper<>());
-    }
-
     default T selectOne(String field, Object value) {
         return selectOne(new QueryWrapper<T>().eq(field, value));
     }
 
+    default List<T> selectList() {
+        return selectList(new QueryWrapper<>());
+    }
+
 }

+ 3 - 3
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/SysDictTypeController.java

@@ -32,7 +32,7 @@ public class SysDictTypeController {
     @GetMapping("/page")
 //    @PreAuthorize("@ss.hasPermi('system:dict:list')")
     public CommonResult<PageResult<SysDictTypeRespVO>> pageDictTypes(@Validated SysDictTypePageReqVO reqVO) {
-        return success(SysDictTypeConvert.INSTANCE.convertPage(dictTypeService.pageDictTypes(reqVO)));
+        return success(SysDictTypeConvert.INSTANCE.convertPage(dictTypeService.getDictTypePage(reqVO)));
     }
 
     @ApiOperation("/查询字典类型详细")
@@ -75,7 +75,7 @@ public class SysDictTypeController {
     @ApiOperation(value = "获得全部字典类型列表", notes = "包括开启 + 禁用的字典类型,主要用于前端的下拉选项")
     // 无需添加权限认证,因为前端全局都需要
     public CommonResult<List<SysDictTypeSimpleRespVO>> listSimpleDictTypes() {
-        List<SysDictTypeDO> list = dictTypeService.listDictTypes();
+        List<SysDictTypeDO> list = dictTypeService.getDictTypeList();
         return success(SysDictTypeConvert.INSTANCE.convertList(list));
     }
 
@@ -84,7 +84,7 @@ public class SysDictTypeController {
 //    @Log(title = "字典类型", businessType = BusinessType.EXPORT)
 //    @PreAuthorize("@ss.hasPermi('system:dict:export')")
     public void export(HttpServletResponse response, @Validated SysDictTypeExportReqVO reqVO) throws IOException {
-        List<SysDictTypeDO> list = dictTypeService.listDictTypes(reqVO);
+        List<SysDictTypeDO> list = dictTypeService.getDictTypeList(reqVO);
         List<SysDictTypeExcelVO> excelTypeList = SysDictTypeConvert.INSTANCE.convertList02(list);
         // 输出
         ExcelUtils.write(response, "字典类型.xls", "类型列表",

+ 4 - 6
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/type/SysDictTypeExportReqVO.java

@@ -5,7 +5,6 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
-import javax.validation.constraints.Size;
 import java.util.Date;
 
 import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@@ -18,18 +17,17 @@ public class SysDictTypeExportReqVO {
     private String name;
 
     @ApiModelProperty(value = "字典类型", example = "sys_common_sex", notes = "模糊匹配")
-    @Size(max = 100, message = "字典类型类型长度不能超过100个字符")
     private String type;
 
     @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
     private Integer status;
 
-    @ApiModelProperty(value = "开始时间", example = "2020-10-24")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private Date beginTime;
+    @ApiModelProperty(value = "开始创建时间")
+    private Date beginCreateTime;
 
-    @ApiModelProperty(value = "结束时间", example = "2020-10-24")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private Date endTime;
+    @ApiModelProperty(value = "结束创建时间")
+    private Date endCreateTime;
 
 }

+ 4 - 4
src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/type/SysDictTypePageReqVO.java

@@ -27,12 +27,12 @@ public class SysDictTypePageReqVO extends PageParam {
     @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
     private Integer status;
 
-    @ApiModelProperty(value = "开始时间", example = "2020-10-24")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private Date beginTime;
+    @ApiModelProperty(value = "开始创建时间")
+    private Date beginCreateTime;
 
-    @ApiModelProperty(value = "结束时间", example = "2020-10-24")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private Date endTime;
+    @ApiModelProperty(value = "结束创建时间")
+    private Date endCreateTime;
 
 }

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/dict/SysDictTypeDO.java

@@ -33,7 +33,7 @@ public class SysDictTypeDO extends BaseDO {
     /**
      * 字典类型
      */
-    @TableField("dict_type")
+    @TableField("`type`")
     private String type;
     /**
      * 状态

+ 8 - 7
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictTypeMapper.java

@@ -16,20 +16,21 @@ public interface SysDictTypeMapper extends BaseMapperX<SysDictTypeDO> {
     default PageResult<SysDictTypeDO> selectPage(SysDictTypePageReqVO reqVO) {
         return selectPage(reqVO, new QueryWrapperX<SysDictTypeDO>()
                 .likeIfPresent("name", reqVO.getName())
-                .likeIfPresent("dict_type", reqVO.getType())
+                .likeIfPresent("`type`", reqVO.getType())
                 .eqIfPresent("status", reqVO.getStatus())
-                .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
+                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()));
     }
 
     default List<SysDictTypeDO> selectList(SysDictTypeExportReqVO reqVO) {
-        return selectList(new QueryWrapperX<SysDictTypeDO>().likeIfPresent("name", reqVO.getName())
-                        .likeIfPresent("dict_type", reqVO.getType())
-                        .eqIfPresent("status", reqVO.getStatus())
-                        .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime()));
+        return selectList(new QueryWrapperX<SysDictTypeDO>()
+                .likeIfPresent("name", reqVO.getName())
+                .likeIfPresent("`type`", reqVO.getType())
+                .eqIfPresent("status", reqVO.getStatus())
+                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()));
     }
 
     default SysDictTypeDO selectByType(String type) {
-        return selectOne(new QueryWrapperX<SysDictTypeDO>().eq("dict_type", type));
+        return selectOne(new QueryWrapperX<SysDictTypeDO>().eq("`type`", type));
     }
 
     default SysDictTypeDO selectByName(String name) {

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java

@@ -58,7 +58,7 @@ public interface SysErrorCodeConstants {
     ErrorCode POST_CODE_DUPLICATE = new ErrorCode(1002005001, "已经存在该标识的岗位");
 
     // ========== 字典类型 1002006000 ==========
-    ErrorCode DICT_TYPE_NOT_FOUND = new ErrorCode(1002006001, "当前字典类型不存在");
+    ErrorCode DICT_TYPE_NOT_EXISTS = new ErrorCode(1002006001, "当前字典类型不存在");
     ErrorCode DICT_TYPE_NOT_ENABLE = new ErrorCode(1002006002, "字典类型不处于开启状态,不允许选择");
     ErrorCode DICT_TYPE_NAME_DUPLICATE = new ErrorCode(1002006003, "已经存在该名字的字典类型");
     ErrorCode DICT_TYPE_TYPE_DUPLICATE = new ErrorCode(1002006004, "已经存在该类型的字典类型");

+ 3 - 3
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeService.java

@@ -22,7 +22,7 @@ public interface SysDictTypeService {
      * @param reqVO 分页请求
      * @return 字典类型分页列表
      */
-    PageResult<SysDictTypeDO> pageDictTypes(SysDictTypePageReqVO reqVO);
+    PageResult<SysDictTypeDO> getDictTypePage(SysDictTypePageReqVO reqVO);
 
     /**
      * 获得字典类型列表
@@ -30,7 +30,7 @@ public interface SysDictTypeService {
      * @param reqVO 列表请求
      * @return 字典类型列表
      */
-    List<SysDictTypeDO> listDictTypes(SysDictTypeExportReqVO reqVO);
+    List<SysDictTypeDO> getDictTypeList(SysDictTypeExportReqVO reqVO);
 
     /**
      * 获得字典类型详情
@@ -75,6 +75,6 @@ public interface SysDictTypeService {
      *
      * @return 字典类型列表
      */
-    List<SysDictTypeDO> listDictTypes();
+    List<SysDictTypeDO> getDictTypeList();
 
 }

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java

@@ -227,7 +227,7 @@ public class SysDictDataServiceImpl implements SysDictDataService {
     private void checkDictTypeValid(String type) {
         SysDictTypeDO dictType = dictTypeService.getDictType(type);
         if (dictType == null) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_FOUND);
+            throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_EXISTS);
         }
         if (!CommonStatusEnum.ENABLE.getStatus().equals(dictType.getStatus())) {
             throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_ENABLE);

+ 11 - 11
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictTypeServiceImpl.java

@@ -1,14 +1,13 @@
 package cn.iocoder.dashboard.modules.system.service.dict.impl;
 
-import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypeCreateReqVO;
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypeExportReqVO;
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypePageReqVO;
 import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypeUpdateReqVO;
 import cn.iocoder.dashboard.modules.system.convert.dict.SysDictTypeConvert;
-import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictTypeMapper;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictTypeMapper;
 import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService;
 import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService;
 import org.springframework.stereotype.Service;
@@ -16,6 +15,7 @@ import org.springframework.stereotype.Service;
 import javax.annotation.Resource;
 import java.util.List;
 
+import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
 
 /**
@@ -33,12 +33,12 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
     private SysDictTypeMapper dictTypeMapper;
 
     @Override
-    public PageResult<SysDictTypeDO> pageDictTypes(SysDictTypePageReqVO reqVO) {
+    public PageResult<SysDictTypeDO> getDictTypePage(SysDictTypePageReqVO reqVO) {
         return dictTypeMapper.selectPage(reqVO);
     }
 
     @Override
-    public List<SysDictTypeDO> listDictTypes(SysDictTypeExportReqVO reqVO) {
+    public List<SysDictTypeDO> getDictTypeList(SysDictTypeExportReqVO reqVO) {
         return dictTypeMapper.selectList(reqVO);
     }
 
@@ -77,14 +77,14 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
         SysDictTypeDO dictType = this.checkDictTypeExists(id);
         // 校验是否有字典数据
         if (dictDataService.countByDictType(dictType.getType()) > 0) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_HAS_CHILDREN);
+            throw exception(DICT_TYPE_HAS_CHILDREN);
         }
         // 删除字典类型
         dictTypeMapper.deleteById(id);
     }
 
     @Override
-    public List<SysDictTypeDO> listDictTypes() {
+    public List<SysDictTypeDO> getDictTypeList() {
         return dictTypeMapper.selectList();
     }
 
@@ -104,10 +104,10 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
         }
         // 如果 id 为空,说明不用比较是否为相同 id 的字典类型
         if (id == null) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_NAME_DUPLICATE);
+            throw exception(DICT_TYPE_NAME_DUPLICATE);
         }
         if (!dictType.getId().equals(id)) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_NAME_DUPLICATE);
+            throw exception(DICT_TYPE_NAME_DUPLICATE);
         }
     }
 
@@ -118,10 +118,10 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
         }
         // 如果 id 为空,说明不用比较是否为相同 id 的字典类型
         if (id == null) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_TYPE_DUPLICATE);
+            throw exception(DICT_TYPE_TYPE_DUPLICATE);
         }
         if (!dictType.getId().equals(id)) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_TYPE_DUPLICATE);
+            throw exception(DICT_TYPE_TYPE_DUPLICATE);
         }
     }
 
@@ -131,7 +131,7 @@ public class SysDictTypeServiceImpl implements SysDictTypeService {
         }
         SysDictTypeDO dictType = dictTypeMapper.selectById(id);
         if (dictType == null) {
-            throw ServiceExceptionUtil.exception(DICT_TYPE_NOT_FOUND);
+            throw exception(DICT_TYPE_NOT_EXISTS);
         }
         return dictType;
     }

+ 31 - 0
src/main/java/cn/iocoder/dashboard/util/collection/ArrayUtils.java

@@ -0,0 +1,31 @@
+package cn.iocoder.dashboard.util.collection;
+
+import cn.hutool.core.util.ArrayUtil;
+
+/**
+ * Array 工具类
+ *
+ * @author 芋道源码
+ */
+public class ArrayUtils {
+
+    /**
+     * 将 object 和 newElements 合并成一个数组
+     *
+     * @param object 对象
+     * @param newElements 数组
+     * @param <T> 泛型
+     * @return 结果数组
+     */
+    @SafeVarargs
+    public static <T> T[] append(T object, T... newElements) {
+        if (object == null) {
+            return newElements;
+        }
+        T[] result = ArrayUtil.newArray(object.getClass(), 1 + newElements.length);
+        result[0] = object;
+        System.arraycopy(newElements, 0, result, 1, newElements.length);
+        return result;
+    }
+
+}

+ 4 - 4
src/main/resources/codegen/java/test/serviceTest.vm

@@ -29,7 +29,7 @@ import static org.mockito.Mockito.*;
 ## 字段模板
 #macro(getPageCondition $VO)
        // mock 数据
-       ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class, o -> {); // 等会查询到
+       ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class, o -> { // 等会查询到
        #foreach ($column in $columns)
        #if (${column.listOperation})
        #set ($JavaField = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})##首字母大写
@@ -123,7 +123,7 @@ public class ${table.className}ServiceTest extends BaseSpringBootUnitTest {
         // 调用
         ${classNameVar}Service.delete${simpleClassName}(id);
        // 校验数据不存在了
-       assertNull(configMapper.selectById(id));
+       assertNull(${classNameVar}Mapper.selectById(id));
     }
 
     @Test
@@ -140,7 +140,7 @@ public class ${table.className}ServiceTest extends BaseSpringBootUnitTest {
        #getPageCondition("PageReqVO")
 
        // 调用
-       PageResult<${table.className}DO> pageResult = configService.getConfigPage(reqVO);
+       PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(reqVO);
        // 断言
        assertEquals(1, pageResult.getTotal());
        assertEquals(1, pageResult.getList().size());
@@ -152,7 +152,7 @@ public class ${table.className}ServiceTest extends BaseSpringBootUnitTest {
        #getPageCondition("ExportReqVO")
 
        // 调用
-       PageResult<${table.className}DO> list = configService.getConfigPage(reqVO);
+       List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(reqVO);
        // 断言
        assertEquals(1, list.size());
        assertPojoEquals(db${simpleClassName}, list.get(0));

+ 10 - 8
src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceTest.java

@@ -1,6 +1,5 @@
 package cn.iocoder.dashboard.modules.infra.service.config;
 
-import cn.hutool.core.util.ArrayUtil;
 import cn.iocoder.dashboard.BaseSpringBootUnitTest;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigCreateReqVO;
@@ -12,6 +11,7 @@ import cn.iocoder.dashboard.modules.infra.dal.mysql.config.InfConfigMapper;
 import cn.iocoder.dashboard.modules.infra.enums.config.InfConfigTypeEnum;
 import cn.iocoder.dashboard.modules.infra.mq.producer.config.InfConfigProducer;
 import cn.iocoder.dashboard.modules.infra.service.config.impl.InfConfigServiceImpl;
+import cn.iocoder.dashboard.util.collection.ArrayUtils;
 import cn.iocoder.dashboard.util.object.ObjectUtils;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.mock.mockito.MockBean;
@@ -20,13 +20,16 @@ import javax.annotation.Resource;
 import java.util.List;
 import java.util.function.Consumer;
 
-import static cn.hutool.core.util.RandomUtil.*;
+import static cn.hutool.core.util.RandomUtil.randomEle;
 import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.*;
-import static cn.iocoder.dashboard.util.AssertUtils.*;
-import static cn.iocoder.dashboard.util.RandomUtils.*;
-import static cn.iocoder.dashboard.util.date.DateUtils.*;
+import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
+import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
+import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
+import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 /**
  * {@link InfConfigServiceImpl} 的单元测试类
@@ -227,12 +230,11 @@ public class InfConfigServiceTest extends BaseSpringBootUnitTest {
     // ========== 随机对象 ==========
 
     @SafeVarargs
-    @SuppressWarnings("unchecked")
     private static InfConfigDO randomInfConfigDO(Consumer<InfConfigDO>... consumers) {
         Consumer<InfConfigDO> consumer = (o) -> {
             o.setType(randomEle(InfConfigTypeEnum.values()).getType()); // 保证 key 的范围
         };
-        return randomPojo(InfConfigDO.class, ArrayUtil.append(new Consumer[]{consumer}, consumers));
+        return randomPojo(InfConfigDO.class, ArrayUtils.append(consumer, consumers));
     }
 
 }

+ 263 - 0
src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictTypeServiceTest.java

@@ -0,0 +1,263 @@
+package cn.iocoder.dashboard.modules.system.service.dict;
+
+import cn.iocoder.dashboard.BaseSpringBootUnitTest;
+import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
+import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypeCreateReqVO;
+import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypeExportReqVO;
+import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypePageReqVO;
+import cn.iocoder.dashboard.modules.system.controller.dict.vo.type.SysDictTypeUpdateReqVO;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO;
+import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictTypeMapper;
+import cn.iocoder.dashboard.modules.system.service.dict.impl.SysDictTypeServiceImpl;
+import cn.iocoder.dashboard.util.collection.ArrayUtils;
+import cn.iocoder.dashboard.util.object.ObjectUtils;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.function.Consumer;
+
+import static cn.hutool.core.util.RandomUtil.randomEle;
+import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
+import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
+import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
+import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
+import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+/**
+* {@link SysDictTypeServiceImpl} 的单元测试类
+*
+* @author 芋艿
+*/
+public class SysDictTypeServiceTest extends BaseSpringBootUnitTest {
+
+    @Resource
+    private SysDictTypeServiceImpl dictTypeService;
+
+    @Resource
+    private SysDictTypeMapper dictTypeMapper;
+    @MockBean
+    private SysDictDataService dictDataService;
+
+    @Test
+    public void testGetDictTypePage() {
+       // mock 数据
+       SysDictTypeDO dbDictType = randomPojo(SysDictTypeDO.class, o -> { // 等会查询到
+           o.setName("yunai");
+           o.setType("芋艿");
+           o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+           o.setCreateTime(buildTime(2021, 1, 15));
+       });
+       dictTypeMapper.insert(dbDictType);
+       // 测试 name 不匹配
+       dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setName("tudou")));
+       // 测试 type 不匹配
+       dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setType("土豆")));
+       // 测试 status 不匹配
+       dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+       // 测试 createTime 不匹配
+       dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1))));
+       // 准备参数
+       SysDictTypePageReqVO reqVO = new SysDictTypePageReqVO();
+       reqVO.setName("nai");
+       reqVO.setType("艿");
+       reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+       reqVO.setBeginCreateTime(buildTime(2021, 1, 10));
+       reqVO.setEndCreateTime(buildTime(2021, 1, 20));
+
+       // 调用
+       PageResult<SysDictTypeDO> pageResult = dictTypeService.getDictTypePage(reqVO);
+       // 断言
+       assertEquals(1, pageResult.getTotal());
+       assertEquals(1, pageResult.getList().size());
+       assertPojoEquals(dbDictType, pageResult.getList().get(0));
+    }
+
+    @Test
+    public void testGetDictTypeList() {
+        // mock 数据
+        SysDictTypeDO dbDictType = randomPojo(SysDictTypeDO.class, o -> { // 等会查询到
+            o.setName("yunai");
+            o.setType("芋艿");
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus());
+            o.setCreateTime(buildTime(2021, 1, 15));
+        });
+        dictTypeMapper.insert(dbDictType);
+        // 测试 name 不匹配
+        dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setName("tudou")));
+        // 测试 type 不匹配
+        dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setType("土豆")));
+        // 测试 status 不匹配
+        dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
+        // 测试 createTime 不匹配
+        dictTypeMapper.insert(ObjectUtils.clone(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1))));
+        // 准备参数
+        SysDictTypeExportReqVO reqVO = new SysDictTypeExportReqVO();
+        reqVO.setName("nai");
+        reqVO.setType("艿");
+        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
+        reqVO.setBeginCreateTime(buildTime(2021, 1, 10));
+        reqVO.setEndCreateTime(buildTime(2021, 1, 20));
+
+        // 调用
+        List<SysDictTypeDO> list = dictTypeService.getDictTypeList(reqVO);
+        // 断言
+        assertEquals(1, list.size());
+        assertPojoEquals(dbDictType, list.get(0));
+    }
+
+    @Test
+    public void testGetDictType() {
+        // mock 数据
+        SysDictTypeDO dbDictType = randomDictTypeDO();
+        dictTypeMapper.insert(dbDictType);
+        // 准备参数
+        String type = dbDictType.getType();
+
+        // 调用
+        SysDictTypeDO dictType = dictTypeService.getDictType(type);
+        // 断言
+        assertNotNull(dictType);
+        assertPojoEquals(dbDictType, dictType);
+    }
+
+    @Test
+    public void testCreateDictType_success() {
+        // 准备参数
+        SysDictTypeCreateReqVO reqVO = randomPojo(SysDictTypeCreateReqVO.class,
+                o -> o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()));
+
+        // 调用
+        Long dictTypeId = dictTypeService.createDictType(reqVO);
+        // 断言
+        assertNotNull(dictTypeId);
+        // 校验记录的属性是否正确
+        SysDictTypeDO dictType = dictTypeMapper.selectById(dictTypeId);
+        assertPojoEquals(reqVO, dictType);
+    }
+
+    @Test
+    public void testCreateDictType_nameDuplicate() {
+        // mock 数据
+        SysDictTypeDO dbDictType = randomDictTypeDO();
+        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        SysDictTypeCreateReqVO reqVO = randomPojo(SysDictTypeCreateReqVO.class,
+                o -> o.setName(dbDictType.getName())); // 模拟 name 重复
+
+        // 调用, 并断言异常
+        assertServiceException(() -> dictTypeService.createDictType(reqVO), DICT_TYPE_NAME_DUPLICATE);
+    }
+
+    @Test
+    public void testCreateDictType_typeDuplicate() {
+        // mock 数据
+        SysDictTypeDO dbDictType = randomDictTypeDO();
+        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        SysDictTypeCreateReqVO reqVO = randomPojo(SysDictTypeCreateReqVO.class,
+                o -> o.setType(dbDictType.getType())); // 模拟 type 重复
+
+        // 调用, 并断言异常
+        assertServiceException(() -> dictTypeService.createDictType(reqVO), DICT_TYPE_TYPE_DUPLICATE);
+    }
+
+    @Test
+    public void testUpdateDictType_success() {
+        // mock 数据
+        SysDictTypeDO dbDictType = randomDictTypeDO();
+        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        SysDictTypeUpdateReqVO reqVO = randomPojo(SysDictTypeUpdateReqVO.class, o -> {
+            o.setId(dbDictType.getId()); // 设置更新的 ID
+            o.setStatus(randomEle(CommonStatusEnum.values()).getStatus());
+        });
+
+        // 调用
+        dictTypeService.updateDictType(reqVO);
+        // 校验是否更新正确
+        SysDictTypeDO dictType = dictTypeMapper.selectById(reqVO.getId()); // 获取最新的
+        assertPojoEquals(reqVO, dictType);
+    }
+
+    @Test
+    public void testUpdateDictType_notExists() {
+        // 准备参数
+        SysDictTypeUpdateReqVO reqVO = randomPojo(SysDictTypeUpdateReqVO.class);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> dictTypeService.updateDictType(reqVO), DICT_TYPE_NOT_EXISTS);
+    }
+
+    @Test
+    public void testUpdateDictType_nameDuplicate() {
+        // mock 数据,稍后更新它
+        SysDictTypeDO dbDictType = randomDictTypeDO();
+        dictTypeMapper.insert(dbDictType);
+        // mock 数据,ks稍后模拟重复它的名字
+        SysDictTypeDO nameDictType = randomDictTypeDO();
+        dictTypeMapper.insert(nameDictType);
+        // 准备参数
+        SysDictTypeUpdateReqVO reqVO = randomPojo(SysDictTypeUpdateReqVO.class, o -> {
+            o.setId(dbDictType.getId()); // 设置更新的 ID
+            o.setName(nameDictType.getName()); // 模拟 name 重复
+        });
+
+        // 调用, 并断言异常
+        assertServiceException(() -> dictTypeService.updateDictType(reqVO), DICT_TYPE_NAME_DUPLICATE);
+    }
+
+    @Test
+    public void testDeleteDictType_success() {
+        // mock 数据
+        SysDictTypeDO dbDictType = randomDictTypeDO();
+        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbDictType.getId();
+
+        // 调用
+        dictTypeService.deleteDictType(id);
+        // 校验数据不存在了
+        assertNull(dictTypeMapper.selectById(id));
+    }
+
+    @Test
+    public void testDeleteDictType_notExists() {
+        // 准备参数
+        Long id = randomLongId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeleteDictType_hasChildren() {
+        // mock 数据
+        SysDictTypeDO dbDictType = randomDictTypeDO();
+        dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbDictType.getId();
+        // mock 方法
+        when(dictDataService.countByDictType(eq(dbDictType.getType()))).thenReturn(1);
+
+        // 调用, 并断言异常
+        assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN);
+    }
+
+    // ========== 随机对象 ==========
+
+    @SafeVarargs
+    private static SysDictTypeDO randomDictTypeDO(Consumer<SysDictTypeDO>... consumers) {
+        Consumer<SysDictTypeDO> consumer = (o) -> {
+            o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
+        };
+        return randomPojo(SysDictTypeDO.class, ArrayUtils.append(consumer, consumers));
+    }
+
+}

+ 0 - 1
src/test/java/cn/iocoder/dashboard/modules/system/service/package-info.java

@@ -1 +0,0 @@
-package cn.iocoder.dashboard.modules.system.service;

+ 1 - 0
src/test/resources/sql/clean.sql

@@ -7,3 +7,4 @@ DELETE FROM "sys_dict_data";
 DELETE FROM "sys_role";
 DELETE FROM "sys_role_menu";
 DELETE FROM "sys_menu";
+DELETE FROM "sys_dict_type";

+ 14 - 0
src/test/resources/sql/create_tables.sql

@@ -100,3 +100,17 @@ CREATE TABLE IF NOT EXISTS "sys_menu" (
     "deleted" bit NOT NULL DEFAULT FALSE,
     PRIMARY KEY ("id")
 ) COMMENT '菜单权限表';
+
+CREATE TABLE "sys_dict_type" (
+    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "name" varchar(100) NOT NULL DEFAULT '',
+    "type" varchar(100) NOT NULL DEFAULT '',
+    "status" tinyint NOT NULL DEFAULT '0',
+    "remark" varchar(500) DEFAULT NULL,
+    "create_by" varchar(64) DEFAULT '',
+    "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "update_by" varchar(64) DEFAULT '',
+    "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    "deleted" bit NOT NULL DEFAULT FALSE,
+    PRIMARY KEY ("id")
+) COMMENT '字典类型表';