diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dict/DictTypeServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dict/DictTypeServiceImpl.java index 0c669ba4a..04797dcf0 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dict/DictTypeServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/dict/DictTypeServiceImpl.java @@ -1,8 +1,7 @@ package com.cf.imes.module.system.service.dict; -import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.cf.imes.framework.common.enums.DeletedCodeEnum; import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.pojo.PageResult; @@ -86,8 +85,12 @@ public class DictTypeServiceImpl implements DictTypeService { // 字典类型发生改变,更新关联字典数据 String oldDictTypeDOType = oldDictTypeDO.getType(); - if (ObjectUtil.isAllNotEmpty(oldDictTypeDOType, updateReqVOType) && ObjectUtil.notEqual(oldDictTypeDOType, updateReqVOType)) { - dictDataMapper.update(new LambdaUpdateWrapper().set(DictDataDO::getDictType, updateReqVOType).eq(DictDataDO::getDictType, oldDictTypeDOType).eq(DictDataDO::getStatus, DeletedCodeEnum.NOT_DELETED.getStatus())); + if (ObjectUtil.notEqual(oldDictTypeDOType, updateReqVOType)) { + UpdateWrapper wrapper = new UpdateWrapper<>(); + wrapper.set("dict_type", updateReqVOType); + wrapper.eq("dict_type", oldDictTypeDOType); + wrapper.eq("status", DeletedCodeEnum.NOT_DELETED.getStatus()); + dictDataMapper.update(wrapper); } } @@ -125,9 +128,6 @@ public class DictTypeServiceImpl implements DictTypeService { @VisibleForTesting void validateDictTypeUnique(Long id, String type) { - if (CharSequenceUtil.isEmpty(type)) { - return; - } DictTypeDO dictType = dictTypeMapper.selectByType(type); if (dictType == null) { return; diff --git a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/controller/admin/dict/DictTypeControllerTest.java b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/controller/admin/dict/DictTypeControllerTest.java new file mode 100644 index 000000000..355be534d --- /dev/null +++ b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/controller/admin/dict/DictTypeControllerTest.java @@ -0,0 +1,192 @@ +package com.cf.imes.module.system.controller.admin.dict; + +import com.cf.imes.framework.common.enums.CommonStatusEnum; +import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.framework.excel.core.util.ExcelUtils; +import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypeRespVO; +import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; +import com.cf.imes.module.system.dal.dataobject.dict.DictTypeDO; +import com.cf.imes.module.system.service.dict.DictTypeService; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +/** + * + * + * @author Gqr + * @since 2026/1/14 17:25 + */ +@WebMvcTest(controllers = DictTypeController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class) +public class DictTypeControllerTest { + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private DictTypeService dictTypeService; + + @Autowired + private ObjectMapper objectMapper; + + @Test + void testCreateDictType_success() throws Exception { + DictTypeSaveReqVO reqVO = new DictTypeSaveReqVO(); + reqVO.setName("测试类型"); + reqVO.setType("test_type"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + when(dictTypeService.createDictType(any())).thenReturn(100L); + + mockMvc.perform(post("/system/dict-type/create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(reqVO))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(100)); + + verify(dictTypeService).createDictType(any()); + } + + @Test + void testUpdateDictType_success() throws Exception { + DictTypeSaveReqVO reqVO = new DictTypeSaveReqVO(); + reqVO.setId(1L); + reqVO.setName("类型B"); + reqVO.setType("typeB"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + + doNothing().when(dictTypeService).updateDictType(any()); + + mockMvc.perform(put("/system/dict-type/update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(reqVO))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(true)); + + verify(dictTypeService).updateDictType(any()); + } + + @Test + void testDeleteDictType_success() throws Exception { + doNothing().when(dictTypeService).deleteDictType(1L); + + mockMvc.perform(delete("/system/dict-type/delete") + .param("id", "1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(true)); + + verify(dictTypeService).deleteDictType(1L); + } + + + @Test + void testPageDictTypes_success() throws Exception { + PageResult pageResult = new PageResult<>(); + DictTypeDO dictTypeDO = new DictTypeDO(); + dictTypeDO.setId(1L); + dictTypeDO.setName("类型C"); + dictTypeDO.setType("typeC"); + pageResult.setList(List.of(dictTypeDO)); + pageResult.setTotal(1L); + + when(dictTypeService.getDictTypePage(any())).thenReturn(pageResult); + + mockMvc.perform(get("/system/dict-type/page") + .param("pageNo", "1") + .param("pageSize", "10")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.list[0].id").value(1)) + .andExpect(jsonPath("$.data.list[0].name").value("类型C")) + .andExpect(jsonPath("$.data.list[0].type").value("typeC")); + } + + @Test + void testGetDictType_success() throws Exception { + DictTypeDO dictTypeDO = new DictTypeDO(); + dictTypeDO.setId(1L); + dictTypeDO.setName("类型D"); + dictTypeDO.setType("typeD"); + + when(dictTypeService.getDictType(1L)).thenReturn(dictTypeDO); + + mockMvc.perform(get("/system/dict-type/get") + .param("id", "1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.id").value(1)) + .andExpect(jsonPath("$.data.name").value("类型D")) + .andExpect(jsonPath("$.data.type").value("typeD")); + } + + @Test + void testGetSimpleDictTypeList_success() throws Exception { + DictTypeDO dictTypeDO = new DictTypeDO(); + dictTypeDO.setId(1L); + dictTypeDO.setName("类型E"); + dictTypeDO.setType("typeE"); + + when(dictTypeService.getDictTypeList()).thenReturn(List.of(dictTypeDO)); + + mockMvc.perform(get("/system/dict-type/list-all-simple")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data[0].id").value(1)) + .andExpect(jsonPath("$.data[0].name").value("类型E")) + .andExpect(jsonPath("$.data[0].type").value("typeE")); + } + + @Test + void testExport_success() throws Exception { + // mock Service 返回分页数据 + DictTypeDO dictTypeDO = new DictTypeDO(); + dictTypeDO.setId(1L); + dictTypeDO.setName("类型A"); + dictTypeDO.setType("typeA"); + + PageResult pageResult = new PageResult<>(); + pageResult.setList(List.of(dictTypeDO)); + when(dictTypeService.getDictTypePage(any())).thenReturn(pageResult); + + // mock ExcelUtils.write 静态方法 + try (MockedStatic excelMock = mockStatic(ExcelUtils.class)) { + + mockMvc.perform(get("/system/dict-type/export") + .param("pageNo", "1") + .param("pageSize", "10")) + .andExpect(status().isOk()); + + // 验证 ExcelUtils.write 被调用 + excelMock.verify(() -> ExcelUtils.write( + any(HttpServletResponse.class), + eq("字典类型.xls"), + eq("数据"), + eq(DictTypeRespVO.class), + anyList() + )); + } + + // 验证 Service 被调用 + verify(dictTypeService).getDictTypePage(any()); + } +} diff --git a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/dict/DictTypeServiceImplTest.java b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/dict/DictTypeServiceImplTest.java index 5691e2a74..7d942f8f8 100644 --- a/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/dict/DictTypeServiceImplTest.java +++ b/cf-module-system/cf-module-system-biz/src/test/java/com/cf/imes/module/system/service/dict/DictTypeServiceImplTest.java @@ -1,271 +1,297 @@ package com.cf.imes.module.system.service.dict; -import com.cf.imes.framework.common.enums.CommonStatusEnum; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.cf.imes.framework.common.pojo.PageResult; -import com.cf.imes.framework.common.util.collection.ArrayUtils; -import com.cf.imes.framework.test.core.ut.BaseDbUnitTest; +import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest; import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypePageReqVO; import com.cf.imes.module.system.controller.admin.dict.vo.type.DictTypeSaveReqVO; import com.cf.imes.module.system.dal.dataobject.dict.DictTypeDO; +import com.cf.imes.module.system.dal.mysql.dict.DictDataMapper; import com.cf.imes.module.system.dal.mysql.dict.DictTypeMapper; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; -import jakarta.annotation.Resource; import java.util.List; -import java.util.function.Consumer; -import static cn.hutool.core.util.RandomUtil.randomEle; -import static com.cf.imes.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; -import static com.cf.imes.framework.common.util.date.LocalDateTimeUtils.buildTime; -import static com.cf.imes.framework.common.util.object.ObjectUtils.cloneIgnoreId; -import static com.cf.imes.framework.test.core.util.AssertUtils.assertPojoEquals; import static com.cf.imes.framework.test.core.util.AssertUtils.assertServiceException; -import static com.cf.imes.framework.test.core.util.RandomUtils.*; -import static com.cf.imes.module.system.enums.ErrorCodeConstants.*; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.DICT_TYPE_HAS_CHILDREN; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.DICT_TYPE_NAME_DUPLICATE; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.DICT_TYPE_NOT_EXISTS; +import static com.cf.imes.module.system.enums.ErrorCodeConstants.DICT_TYPE_TYPE_DUPLICATE; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -@Import(DictTypeServiceImpl.class) -public class DictTypeServiceImplTest extends BaseDbUnitTest { +public class DictTypeServiceImplTest extends BaseMockitoUnitTest { - @Resource + @InjectMocks private DictTypeServiceImpl dictTypeService; - @Resource + @Mock private DictTypeMapper dictTypeMapper; - @MockBean + + @Mock + private DictDataMapper dictDataMapper; + + @Mock private DictDataService dictDataService; @Test - public void testGetDictTypePage() { - // mock 数据 - DictTypeDO dbDictType = randomPojo(DictTypeDO.class, o -> { // 等会查询到 - o.setName("yunai"); - o.setType("晨丰"); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setCreateTime(buildTime(2021, 1, 15)); - }); - dictTypeMapper.insert(dbDictType); - // 测试 name 不匹配 - dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setName("tudou"))); - // 测试 type 不匹配 - dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setType("土豆"))); - // 测试 status 不匹配 - dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); - // 测试 createTime 不匹配 - dictTypeMapper.insert(cloneIgnoreId(dbDictType, o -> o.setCreateTime(buildTime(2021, 1, 1)))); - // 准备参数 - DictTypePageReqVO reqVO = new DictTypePageReqVO(); - reqVO.setName("nai"); - reqVO.setType("艿"); - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); - reqVO.setCreateTime(buildBetweenTime(2021, 1, 10, 2021, 1, 20)); - - // 调用 - PageResult pageResult = dictTypeService.getDictTypePage(reqVO); - // 断言 - assertEquals(1, pageResult.getTotal()); - assertEquals(1, pageResult.getList().size()); - assertPojoEquals(dbDictType, pageResult.getList().get(0)); - } - - @Test - public void testGetDictType_id() { - // mock 数据 - DictTypeDO dbDictType = randomDictTypeDO(); - dictTypeMapper.insert(dbDictType); + void testGetDictTypePage_success() { // 准备参数 - Long id = dbDictType.getId(); + DictTypePageReqVO reqVO = new DictTypePageReqVO(); + + PageResult pageResult = new PageResult<>(); + pageResult.setTotal(1L); + + // mock mapper + when(dictTypeMapper.selectPage(reqVO)).thenReturn(pageResult); // 调用 - DictTypeDO dictType = dictTypeService.getDictType(id); + PageResult result = dictTypeService.getDictTypePage(reqVO); + // 断言 - assertNotNull(dictType); - assertPojoEquals(dbDictType, dictType); + assertSame(pageResult, result); + + // 校验调用 + verify(dictTypeMapper).selectPage(reqVO); } @Test - public void testGetDictType_type() { - // mock 数据 - DictTypeDO dbDictType = randomDictTypeDO(); - dictTypeMapper.insert(dbDictType); - // 准备参数 - String type = dbDictType.getType(); + void testGetDictTypeById_success() { + DictTypeDO dictType = new DictTypeDO(); + dictType.setId(1L); - // 调用 - DictTypeDO dictType = dictTypeService.getDictType(type); - // 断言 - assertNotNull(dictType); - assertPojoEquals(dbDictType, dictType); + when(dictTypeMapper.selectById(1L)).thenReturn(dictType); + + DictTypeDO result = dictTypeService.getDictType(1L); + + assertSame(dictType, result); + verify(dictTypeMapper).selectById(1L); } @Test - public void testCreateDictType_success() { - // 准备参数 - DictTypeSaveReqVO reqVO = randomPojo(DictTypeSaveReqVO.class, - o -> o.setStatus(randomEle(CommonStatusEnum.values()).getStatus())) - .setId(null); // 避免 id 被赋值 + void testGetDictTypeByType_success() { + DictTypeDO dictType = new DictTypeDO(); + dictType.setType("system"); - // 调用 - Long dictTypeId = dictTypeService.createDictType(reqVO); - // 断言 - assertNotNull(dictTypeId); - // 校验记录的属性是否正确 - DictTypeDO dictType = dictTypeMapper.selectById(dictTypeId); - assertPojoEquals(reqVO, dictType, "id"); + when(dictTypeMapper.selectByType("system")).thenReturn(dictType); + + DictTypeDO result = dictTypeService.getDictType("system"); + + assertSame(dictType, result); + verify(dictTypeMapper).selectByType("system"); } @Test - public void testUpdateDictType_success() { - // mock 数据 - DictTypeDO dbDictType = randomDictTypeDO(); - dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据 - // 准备参数 - DictTypeSaveReqVO reqVO = randomPojo(DictTypeSaveReqVO.class, o -> { - o.setId(dbDictType.getId()); // 设置更新的 ID - o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); - }); + void testCreateDictType_success() { + DictTypeSaveReqVO reqVO = new DictTypeSaveReqVO(); + reqVO.setName("系统配置"); + reqVO.setType("system"); + + // mock 唯一性校验 + when(dictTypeMapper.selectByName("系统配置")).thenReturn(null); + when(dictTypeMapper.selectByType("system")).thenReturn(null); + + // mock insert:模拟 MyBatis 回写 id + doAnswer(invocation -> { + DictTypeDO arg = invocation.getArgument(0); + arg.setId(1L); + return 1; + }).when(dictTypeMapper).insert(any(DictTypeDO.class)); + + Long id = dictTypeService.createDictType(reqVO); + + assertEquals(1L, id); + verify(dictTypeMapper).insert(any(DictTypeDO.class)); + } + + @Test + void testUpdateDictType_success_noTypeChange() { + DictTypeSaveReqVO reqVO = new DictTypeSaveReqVO(); + reqVO.setId(1L); + reqVO.setName("系统"); + reqVO.setType("system"); + + DictTypeDO old = new DictTypeDO(); + old.setId(1L); + old.setType("system"); + + when(dictTypeMapper.selectById(1L)).thenReturn(old); + when(dictTypeMapper.selectByName("系统")).thenReturn(null); + when(dictTypeMapper.selectByType("system")).thenReturn(old); + when(dictTypeMapper.updateById(any(DictTypeDO.class))).thenReturn(1); - // 调用 dictTypeService.updateDictType(reqVO); - // 校验是否更新正确 - DictTypeDO dictType = dictTypeMapper.selectById(reqVO.getId()); // 获取最新的 - assertPojoEquals(reqVO, dictType); + + verify(dictTypeMapper).updateById(any(DictTypeDO.class)); + verify(dictDataMapper, Mockito.never()).update(any()); } @Test - public void testDeleteDictType_success() { - // mock 数据 - DictTypeDO dbDictType = randomDictTypeDO(); - dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbDictType.getId(); + void testUpdateDictType_success_typeChanged() { + DictTypeSaveReqVO reqVO = new DictTypeSaveReqVO(); + reqVO.setId(1L); + reqVO.setType("new_type"); + + DictTypeDO old = new DictTypeDO(); + old.setId(1L); + old.setType("old_type"); + + when(dictTypeMapper.selectById(1L)).thenReturn(old); + when(dictTypeMapper.selectByType("new_type")).thenReturn(null); + when(dictTypeMapper.updateById(any(DictTypeDO.class))).thenReturn(1); + when(dictDataMapper.update(any(UpdateWrapper.class))).thenReturn(1); + + dictTypeService.updateDictType(reqVO); + + // 校验 dict_data 被批量更新 + verify(dictDataMapper).update( + argThat((UpdateWrapper wrapper) -> + wrapper.getSqlSet().contains("dict_type") + ) + ); + - // 调用 - dictTypeService.deleteDictType(id); - // 校验数据不存在了 - assertNull(dictTypeMapper.selectById(id)); } @Test - public void testDeleteDictType_hasChildren() { - // mock 数据 - DictTypeDO dbDictType = randomDictTypeDO(); - dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据 - // 准备参数 - Long id = dbDictType.getId(); - // mock 方法 - when(dictDataService.getDictDataCountByDictType(eq(dbDictType.getType()))).thenReturn(1L); + void testDeleteDictType_success() { + DictTypeDO dictType = new DictTypeDO(); + dictType.setId(1L); + dictType.setType("system"); - // 调用, 并断言异常 - assertServiceException(() -> dictTypeService.deleteDictType(id), DICT_TYPE_HAS_CHILDREN); + when(dictTypeMapper.selectById(1L)).thenReturn(dictType); + when(dictDataService.getDictDataCountByDictType("system")).thenReturn(0L); + + dictTypeService.deleteDictType(1L); + + verify(dictTypeMapper).updateToDelete(eq(1L), any()); } @Test - public void testGetDictTypeList() { - // 准备参数 - DictTypeDO dictTypeDO01 = randomDictTypeDO(); - dictTypeMapper.insert(dictTypeDO01); - DictTypeDO dictTypeDO02 = randomDictTypeDO(); - dictTypeMapper.insert(dictTypeDO02); - // mock 方法 + void testDeleteDictType_hasChildren() { + DictTypeDO dictType = new DictTypeDO(); + dictType.setId(1L); + dictType.setType("system"); - // 调用 - List dictTypeDOList = dictTypeService.getDictTypeList(); - // 断言 - assertEquals(2, dictTypeDOList.size()); - assertPojoEquals(dictTypeDO01, dictTypeDOList.get(0)); - assertPojoEquals(dictTypeDO02, dictTypeDOList.get(1)); + when(dictTypeMapper.selectById(1L)).thenReturn(dictType); + when(dictDataService.getDictDataCountByDictType("system")).thenReturn(1L); + + assertServiceException(() -> dictTypeService.deleteDictType(1L), DICT_TYPE_HAS_CHILDREN); } @Test - public void testValidateDictDataExists_success() { - // mock 数据 - DictTypeDO dbDictType = randomDictTypeDO(); - dictTypeMapper.insert(dbDictType);// @Sql: 先插入出一条存在的数据 + void testGetDictTypeList_success() { + List list = List.of(new DictTypeDO(), new DictTypeDO()); + when(dictTypeMapper.selectList()).thenReturn(list); - // 调用成功 - dictTypeService.validateDictTypeExists(dbDictType.getId()); + List result = dictTypeService.getDictTypeList(); + + assertSame(list, result); } @Test - public void testValidateDictDataExists_notExists() { - assertServiceException(() -> dictTypeService.validateDictTypeExists(randomLongId()), DICT_TYPE_NOT_EXISTS); + void validateDictTypeNameUnique_notExists_shouldPass() { + // 模拟数据库返回 null,表示该名字不存在 + when(dictTypeMapper.selectByName("newTypeName")).thenReturn(null); + + // 调用方法,不应该抛异常 + dictTypeService.validateDictTypeNameUnique(null, "newTypeName"); + dictTypeService.validateDictTypeNameUnique(1L, "newTypeName"); } @Test - public void testValidateDictTypeUnique_success() { - // 调用,成功 - dictTypeService.validateDictTypeUnique(randomLongId(), randomString()); + void validateDictTypeNameUnique_existsWithNullId_shouldThrow() { + // 模拟数据库返回已有记录 + DictTypeDO existing = new DictTypeDO(); + existing.setId(100L); + when(dictTypeMapper.selectByName("existName")).thenReturn(existing); + + assertServiceException(() -> dictTypeService.validateDictTypeNameUnique(null, "existName"), DICT_TYPE_NAME_DUPLICATE); } @Test - public void testValidateDictTypeUnique_valueDuplicateForCreate() { - // 准备参数 - String type = randomString(); - // mock 数据 - dictTypeMapper.insert(randomDictTypeDO(o -> o.setType(type))); + void validateDictTypeNameUnique_existsWithDifferentId_shouldThrow() { + // 模拟数据库返回已有记录 + DictTypeDO existing = new DictTypeDO(); + existing.setId(100L); + when(dictTypeMapper.selectByName("existName")).thenReturn(existing); - // 调用,校验异常 - assertServiceException(() -> dictTypeService.validateDictTypeUnique(null, type), - DICT_TYPE_TYPE_DUPLICATE); + + assertServiceException(() -> dictTypeService.validateDictTypeNameUnique(200L, "existName"), DICT_TYPE_NAME_DUPLICATE); } @Test - public void testValidateDictTypeUnique_valueDuplicateForUpdate() { - // 准备参数 - Long id = randomLongId(); - String type = randomString(); - // mock 数据 - dictTypeMapper.insert(randomDictTypeDO(o -> o.setType(type))); + void validateDictTypeNameUnique_existsWithSameId_shouldPass() { + // 模拟数据库返回已有记录 + DictTypeDO existing = new DictTypeDO(); + existing.setId(100L); + when(dictTypeMapper.selectByName("existName")).thenReturn(existing); - // 调用,校验异常 - assertServiceException(() -> dictTypeService.validateDictTypeUnique(id, type), - DICT_TYPE_TYPE_DUPLICATE); + // 当 id 与已有记录一致,不抛异常 + dictTypeService.validateDictTypeNameUnique(100L, "existName"); } @Test - public void testValidateDictTypNameUnique_success() { - // 调用,成功 - dictTypeService.validateDictTypeNameUnique(randomLongId(), randomString()); + void validateDictTypeUnique_typeNotExists_shouldPass() { + when(dictTypeMapper.selectByType("newType")).thenReturn(null); + dictTypeService.validateDictTypeUnique(1L, "newType"); } @Test - public void testValidateDictTypeNameUnique_nameDuplicateForCreate() { - // 准备参数 - String name = randomString(); - // mock 数据 - dictTypeMapper.insert(randomDictTypeDO(o -> o.setName(name))); + void validateDictTypeUnique_typeExistsWithNullId_shouldThrow() { + DictTypeDO existing = new DictTypeDO(); + existing.setId(100L); + when(dictTypeMapper.selectByType("existType")).thenReturn(existing); - // 调用,校验异常 - assertServiceException(() -> dictTypeService.validateDictTypeNameUnique(null, name), - DICT_TYPE_NAME_DUPLICATE); + assertServiceException(() -> dictTypeService.validateDictTypeUnique(null, "existType"), DICT_TYPE_TYPE_DUPLICATE); } @Test - public void testValidateDictTypeNameUnique_nameDuplicateForUpdate() { - // 准备参数 - Long id = randomLongId(); - String name = randomString(); - // mock 数据 - dictTypeMapper.insert(randomDictTypeDO(o -> o.setName(name))); + void validateDictTypeUnique_typeExistsWithDifferentId_shouldThrow() { + DictTypeDO existing = new DictTypeDO(); + existing.setId(100L); + when(dictTypeMapper.selectByType("existType")).thenReturn(existing); - // 调用,校验异常 - assertServiceException(() -> dictTypeService.validateDictTypeNameUnique(id, name), - DICT_TYPE_NAME_DUPLICATE); + assertServiceException(() -> dictTypeService.validateDictTypeUnique(200L, "existType"), DICT_TYPE_TYPE_DUPLICATE); } - // ========== 随机对象 ========== + @Test + void validateDictTypeUnique_typeExistsWithSameId_shouldPass() { + DictTypeDO existing = new DictTypeDO(); + existing.setId(100L); + when(dictTypeMapper.selectByType("existType")).thenReturn(existing); - @SafeVarargs - private static DictTypeDO randomDictTypeDO(Consumer... consumers) { - Consumer consumer = (o) -> { - o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 - }; - return randomPojo(DictTypeDO.class, ArrayUtils.append(consumer, consumers)); + dictTypeService.validateDictTypeUnique(100L, "existType"); } + // ================= validateDictTypeExists ================= + @Test + void validateDictTypeExists_idNull_shouldReturnNull() { + assertNull(dictTypeService.validateDictTypeExists(null)); + } + + @Test + void validateDictTypeExists_idNotExists_shouldThrow() { + when(dictTypeMapper.selectById(123L)).thenReturn(null); + + assertServiceException(() -> dictTypeService.validateDictTypeExists(123L), DICT_TYPE_NOT_EXISTS); + } + + @Test + void validateDictTypeExists_idExists_shouldReturnDictType() { + DictTypeDO dictTypeDO = new DictTypeDO(); + dictTypeDO.setId(100L); + when(dictTypeMapper.selectById(100L)).thenReturn(dictTypeDO); + + DictTypeDO result = dictTypeService.validateDictTypeExists(100L); + assertSame(dictTypeDO, result); + } }