Browse Source

完成 config 模块的单元测试

YunaiV 4 years ago
parent
commit
95857ace9a

+ 3 - 1
src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java

@@ -2,6 +2,7 @@ package cn.iocoder.dashboard.common.exception.util;
 
 import cn.iocoder.dashboard.common.exception.ErrorCode;
 import cn.iocoder.dashboard.common.exception.ServiceException;
+import com.google.common.annotations.VisibleForTesting;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -91,7 +92,8 @@ public class ServiceExceptionUtil {
      * @param params         参数
      * @return 格式化后的提示
      */
-    private static String doFormat(int code, String messagePattern, Object... params) {
+    @VisibleForTesting
+    public static String doFormat(int code, String messagePattern, Object... params) {
         StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
         int i = 0;
         int j;

+ 5 - 2
src/main/java/cn/iocoder/dashboard/common/pojo/PageParam.java

@@ -13,14 +13,17 @@ import java.io.Serializable;
 @Data
 public class PageParam implements Serializable {
 
+    private static final Integer PAGE_NO = 1;
+    private static final Integer PAGE_SIZE = 10;
+
     @ApiModelProperty(value = "页码,从 1 开始", required = true,example = "1")
     @NotNull(message = "页码不能为空")
     @Min(value = 1, message = "页码最小值为 1")
-    private Integer pageNo;
+    private Integer pageNo = PAGE_NO;
 
     @ApiModelProperty(value = "每页条数,最大值为 100", required = true, example = "10")
     @NotNull(message = "每页条数不能为空")
     @Range(min = 1, max = 100, message = "条数范围为 [1, 100]")
-    private Integer pageSize;
+    private Integer pageSize = PAGE_SIZE;
 
 }

+ 37 - 0
src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java

@@ -1,6 +1,7 @@
 package cn.iocoder.dashboard.util.date;
 
 import java.time.Duration;
+import java.util.Calendar;
 import java.util.Date;
 
 /**
@@ -22,4 +23,40 @@ public class DateUtils {
         return endTime.getTime() - startTime.getTime();
     }
 
+    /**
+     * 创建指定时间
+     *
+     * @param year        年
+     * @param mouth       月
+     * @param day         日
+     * @return 指定时间
+     */
+    public static Date buildTime(int year, int mouth, int day) {
+        return buildTime(year, mouth, day, 0, 0, 0);
+    }
+
+    /**
+     * 创建指定时间
+     *
+     * @param year        年
+     * @param mouth       月
+     * @param day         日
+     * @param hour        小时
+     * @param minute      分钟
+     * @param second      秒
+     * @return 指定时间
+     */
+    public static Date buildTime(int year, int mouth, int day,
+                                 int hour, int minute, int second) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.YEAR, year);
+        calendar.set(Calendar.MONTH, mouth - 1);
+        calendar.set(Calendar.DAY_OF_MONTH, day);
+        calendar.set(Calendar.HOUR_OF_DAY, hour);
+        calendar.set(Calendar.MINUTE, minute);
+        calendar.set(Calendar.SECOND, second);
+        calendar.set(Calendar.MILLISECOND, 0); // 一般情况下,都是 0 毫秒
+        return calendar.getTime();
+    }
+
 }

+ 22 - 0
src/main/java/cn/iocoder/dashboard/util/object/ObjectUtils.java

@@ -0,0 +1,22 @@
+package cn.iocoder.dashboard.util.object;
+
+import cn.hutool.core.util.ObjectUtil;
+
+import java.util.function.Consumer;
+
+/**
+ * Object 工具类
+ *
+ * @author 芋道源码
+ */
+public class ObjectUtils {
+
+    public static <T> T clone(T object, Consumer<T> consumer) {
+        T result = ObjectUtil.clone(object);
+        if (result != null) {
+            consumer.accept(result);
+        }
+        return result;
+    }
+
+}

+ 131 - 17
src/test/java/cn/iocoder/dashboard/modules/infra/service/config/InfConfigServiceImplTest.java

@@ -1,26 +1,31 @@
 package cn.iocoder.dashboard.modules.infra.service.config;
 
+import cn.hutool.core.util.ArrayUtil;
 import cn.iocoder.dashboard.BaseSpringBootUnitTest;
-import cn.iocoder.dashboard.common.exception.ServiceException;
+import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigCreateReqVO;
+import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigExportReqVO;
+import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigPageReqVO;
 import cn.iocoder.dashboard.modules.infra.controller.config.vo.InfConfigUpdateReqVO;
 import cn.iocoder.dashboard.modules.infra.dal.dataobject.config.InfConfigDO;
 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.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.infra.enums.InfErrorCodeConstants.CONFIG_KEY_DUPLICATE;
-import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.CONFIG_NOT_EXISTS;
-import static cn.iocoder.dashboard.util.AssertUtils.assertExceptionEquals;
+import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.*;
 import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
+import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
 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.times;
 import static org.mockito.Mockito.verify;
@@ -36,11 +41,92 @@ public class InfConfigServiceImplTest extends BaseSpringBootUnitTest {
     @MockBean
     private InfConfigProducer configProducer;
 
+    @Test
+    public void testGetConfigPage() {
+        // mock 数据
+        InfConfigDO dbConfig = randomInfConfigDO(o -> { // 等会查询到
+            o.setName("芋艿");
+            o.setKey("yunai");
+            o.setType(InfConfigTypeEnum.SYSTEM.getType());
+            o.setCreateTime(buildTime(2021, 2, 1));
+        });
+        configMapper.insert(dbConfig);
+        // 测试 name 不匹配
+        configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setName("土豆")));
+        // 测试 key 不匹配
+        configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setKey("tudou")));
+        // 测试 type 不匹配
+        configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setType(InfConfigTypeEnum.CUSTOM.getType())));
+        // 测试 createTime 不匹配
+        configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setCreateTime(buildTime(2021, 1, 1))));
+        // 准备参数
+        InfConfigPageReqVO reqVO = new InfConfigPageReqVO();
+        reqVO.setName("艿");
+        reqVO.setKey("nai");
+        reqVO.setType(InfConfigTypeEnum.SYSTEM.getType());
+        reqVO.setBeginTime(buildTime(2021, 1, 15));
+        reqVO.setEndTime(buildTime(2021, 2, 15));
+
+        // 调用
+        PageResult<InfConfigDO> pageResult = configService.getConfigPage(reqVO);
+        // 断言
+        assertEquals(1, pageResult.getTotal());
+        assertEquals(1, pageResult.getList().size());
+        assertPojoEquals(dbConfig, pageResult.getList().get(0));
+    }
+
+    @Test
+    public void testGetConfigList() {
+        // mock 数据
+        InfConfigDO dbConfig = randomInfConfigDO(o -> { // 等会查询到
+            o.setName("芋艿");
+            o.setKey("yunai");
+            o.setType(InfConfigTypeEnum.SYSTEM.getType());
+            o.setCreateTime(buildTime(2021, 2, 1));
+        });
+        configMapper.insert(dbConfig);
+        // 测试 name 不匹配
+        configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setName("土豆")));
+        // 测试 key 不匹配
+        configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setKey("tudou")));
+        // 测试 type 不匹配
+        configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setType(InfConfigTypeEnum.CUSTOM.getType())));
+        // 测试 createTime 不匹配
+        configMapper.insert(ObjectUtils.clone(dbConfig, o -> o.setCreateTime(buildTime(2021, 1, 1))));
+        // 准备参数
+        InfConfigExportReqVO reqVO = new InfConfigExportReqVO();
+        reqVO.setName("艿");
+        reqVO.setKey("nai");
+        reqVO.setType(InfConfigTypeEnum.SYSTEM.getType());
+        reqVO.setBeginTime(buildTime(2021, 1, 15));
+        reqVO.setEndTime(buildTime(2021, 2, 15));
+
+        // 调用
+        List<InfConfigDO> list = configService.getConfigList(reqVO);
+        // 断言
+        assertEquals(1, list.size());
+        assertPojoEquals(dbConfig, list.get(0));
+    }
+
+    @Test
+    public void testGetConfigByKey() {
+        // mock 数据
+        InfConfigDO dbConfig = randomInfConfigDO();
+        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        String key = dbConfig.getKey();
+
+        // 调用
+        InfConfigDO config = configService.getConfigByKey(key);
+        // 断言
+        assertNotNull(config);
+        assertPojoEquals(dbConfig, config);
+    }
+
     @Test
     public void testCreateConfig_success() {
         // 准备参数
         InfConfigCreateReqVO reqVO = randomPojo(InfConfigCreateReqVO.class);
-        // mock
 
         // 调用
         Long configId = configService.createConfig(reqVO);
@@ -63,11 +149,8 @@ public class InfConfigServiceImplTest extends BaseSpringBootUnitTest {
             o.setKey(reqVO.getKey()); // 模拟 key 重复
         }));
 
-        // 调用
-        ServiceException serviceException = assertThrows(ServiceException.class,
-                () -> configService.createConfig(reqVO));
-        // 断言异常
-        assertExceptionEquals(CONFIG_KEY_DUPLICATE, serviceException);
+        // 调用, 并断言异常
+        assertServiceException(() -> configService.createConfig(reqVO), CONFIG_KEY_DUPLICATE);
     }
 
     @Test
@@ -94,20 +177,51 @@ public class InfConfigServiceImplTest extends BaseSpringBootUnitTest {
         // 准备参数
         InfConfigUpdateReqVO reqVO = randomPojo(InfConfigUpdateReqVO.class);
 
+        // 调用, 并断言异常
+        assertServiceException(() -> configService.updateConfig(reqVO), CONFIG_NOT_EXISTS);
+    }
+
+    @Test
+    public void testDeleteConfig_success() {
+        // mock 数据
+        InfConfigDO dbConfig = randomInfConfigDO(o -> {
+            o.setType(InfConfigTypeEnum.CUSTOM.getType()); // 只能删除 CUSTOM 类型
+        });
+        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbConfig.getId();
+
         // 调用
-        ServiceException serviceException = assertThrows(ServiceException.class,
-                () -> configService.updateConfig(reqVO));
-        // 断言异常
-        assertExceptionEquals(CONFIG_NOT_EXISTS, serviceException);
+        configService.deleteConfig(id);
+        // 校验数据不存在了
+        assertNull(configMapper.selectById(id));
+        // 校验调用
+        verify(configProducer, times(1)).sendConfigRefreshMessage();
+    }
+
+    @Test
+    public void testDeleteConfig_canNotDeleteSystemType() {
+        // mock 数据
+        InfConfigDO dbConfig = randomInfConfigDO(o -> {
+            o.setType(InfConfigTypeEnum.SYSTEM.getType()); // SYSTEM 不允许删除
+        });
+        configMapper.insert(dbConfig);// @Sql: 先插入出一条存在的数据
+        // 准备参数
+        Long id = dbConfig.getId();
+
+        // 调用, 并断言异常
+        assertServiceException(() -> configService.deleteConfig(id), CONFIG_CAN_NOT_DELETE_SYSTEM_TYPE);
     }
 
     // ========== 随机对象 ==========
 
     @SafeVarargs
+    @SuppressWarnings("unchecked")
     private static InfConfigDO randomInfConfigDO(Consumer<InfConfigDO>... consumers) {
-        InfConfigDO config = randomPojo(InfConfigDO.class, consumers);
-        config.setType(randomEle(InfConfigTypeEnum.values()).getType()); // 保证 key 的范围
-        return config;
+        Consumer<InfConfigDO> consumer = (o) -> {
+            o.setType(randomEle(InfConfigTypeEnum.values()).getType()); // 保证 key 的范围
+        };
+        return randomPojo(InfConfigDO.class, ArrayUtil.append(new Consumer[]{consumer}, consumers));
     }
 
 }

+ 13 - 4
src/test/java/cn/iocoder/dashboard/util/AssertUtils.java

@@ -4,11 +4,15 @@ import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ReflectUtil;
 import cn.iocoder.dashboard.common.exception.ErrorCode;
 import cn.iocoder.dashboard.common.exception.ServiceException;
+import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.function.Executable;
 
 import java.lang.reflect.Field;
 import java.util.Arrays;
 
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 /**
  * 单元测试,assert 断言工具类
  *
@@ -47,14 +51,19 @@ public class AssertUtils {
     }
 
     /**
-     * 比对抛出的 ServiceException 是否匹配
+     * 执行方法,校验抛出的 Service 是否符合条件
      *
+     * @param executable 业务异常
      * @param errorCode 错误码对象
-     * @param serviceException 业务异常
+     * @param messageParams 消息参数
      */
-    public static void assertExceptionEquals(ErrorCode errorCode, ServiceException serviceException) {
+    public static void assertServiceException(Executable executable, ErrorCode errorCode, Object... messageParams) {
+        // 调用方法
+        ServiceException serviceException = assertThrows(ServiceException.class, executable);
+        // 校验错误码
         Assertions.assertEquals(errorCode.getCode(), serviceException.getCode(), "错误码不匹配");
-        Assertions.assertEquals(errorCode.getMessage(), serviceException.getMessage(), "错误提示不匹配");
+        String message = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMessage(), messageParams);
+        Assertions.assertEquals(message, serviceException.getMessage(), "错误提示不匹配");
     }
 
 }