Commit 0017a259116cfd31ab45bca69435bd7e09bf77c0
1 parent
7eec9887
feat(mod): module create error branches REQ-MOD-001
Showing
2 changed files
with
62 additions
and
1 deletions
backend/src/main/java/com/xly/erp/module/mod/service/impl/ModuleServiceImpl.java
| ... | ... | @@ -8,15 +8,19 @@ import com.xly.erp.module.mod.dto.CreateModuleDTO; |
| 8 | 8 | import com.xly.erp.module.mod.entity.Module; |
| 9 | 9 | import com.xly.erp.module.mod.mapper.ModuleMapper; |
| 10 | 10 | import com.xly.erp.module.mod.service.ModuleService; |
| 11 | +import org.springframework.dao.DuplicateKeyException; | |
| 11 | 12 | import org.springframework.stereotype.Service; |
| 12 | 13 | import org.springframework.transaction.annotation.Transactional; |
| 13 | 14 | |
| 14 | 15 | import java.time.LocalDateTime; |
| 16 | +import java.util.Set; | |
| 15 | 17 | |
| 16 | 18 | @Service |
| 17 | 19 | @Transactional(rollbackFor = Exception.class) |
| 18 | 20 | public class ModuleServiceImpl implements ModuleService { |
| 19 | 21 | |
| 22 | + private static final Set<String> DISPLAY_TYPES = Set.of("手机端", "前端业务", "系统配置", "接口"); | |
| 23 | + | |
| 20 | 24 | private final ModuleMapper moduleMapper; |
| 21 | 25 | private final TenantProperties tenant; |
| 22 | 26 | private final StubSecurityProperties stub; |
| ... | ... | @@ -31,6 +35,9 @@ public class ModuleServiceImpl implements ModuleService { |
| 31 | 35 | |
| 32 | 36 | @Override |
| 33 | 37 | public Integer create(CreateModuleDTO dto) { |
| 38 | + if (!DISPLAY_TYPES.contains(dto.getSDisplayType())) { | |
| 39 | + throw new BizException(40010, "显示类型枚举不合法"); | |
| 40 | + } | |
| 34 | 41 | if (dto.getIParentId() != null && !moduleMapper.existsActiveById(dto.getIParentId())) { |
| 35 | 42 | throw new BizException(40021, "父模块不存在或已删除"); |
| 36 | 43 | } |
| ... | ... | @@ -51,7 +58,11 @@ public class ModuleServiceImpl implements ModuleService { |
| 51 | 58 | m.setSCreatedBy(authedUserNo != null ? authedUserNo : stub.getStubUserNo()); |
| 52 | 59 | m.setBDeleted(false); |
| 53 | 60 | |
| 54 | - moduleMapper.insert(m); | |
| 61 | + try { | |
| 62 | + moduleMapper.insert(m); | |
| 63 | + } catch (DuplicateKeyException e) { | |
| 64 | + throw new BizException(40020, "存储过程名称已存在"); | |
| 65 | + } | |
| 55 | 66 | return m.getIIncrement(); |
| 56 | 67 | } |
| 57 | 68 | } | ... | ... |
backend/src/test/java/com/xly/erp/module/mod/service/ModuleServiceImplTest.java
| ... | ... | @@ -11,8 +11,12 @@ import org.junit.jupiter.api.AfterEach; |
| 11 | 11 | import org.junit.jupiter.api.BeforeEach; |
| 12 | 12 | import org.junit.jupiter.api.Test; |
| 13 | 13 | import org.mockito.ArgumentCaptor; |
| 14 | +import org.springframework.dao.DuplicateKeyException; | |
| 15 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | |
| 14 | 16 | import org.springframework.security.core.context.SecurityContextHolder; |
| 15 | 17 | |
| 18 | +import java.util.Collections; | |
| 19 | + | |
| 16 | 20 | import static org.assertj.core.api.Assertions.assertThat; |
| 17 | 21 | import static org.assertj.core.api.Assertions.assertThatThrownBy; |
| 18 | 22 | import static org.mockito.ArgumentMatchers.any; |
| ... | ... | @@ -82,6 +86,52 @@ class ModuleServiceImplTest { |
| 82 | 86 | verify(moduleMapper, never()).insert(any(Module.class)); |
| 83 | 87 | } |
| 84 | 88 | |
| 89 | + @Test | |
| 90 | + void createWithInvalidDisplayType_throws40010() { | |
| 91 | + CreateModuleDTO dto = baseDto(); | |
| 92 | + dto.setSDisplayType("未知"); | |
| 93 | + | |
| 94 | + assertThatThrownBy(() -> service.create(dto)) | |
| 95 | + .isInstanceOf(BizException.class) | |
| 96 | + .hasFieldOrPropertyWithValue("code", 40010); | |
| 97 | + verify(moduleMapper, never()).insert(any(Module.class)); | |
| 98 | + } | |
| 99 | + | |
| 100 | + @Test | |
| 101 | + void createWithNullParentId_skipsParentCheck() { | |
| 102 | + CreateModuleDTO dto = baseDto(); | |
| 103 | + dto.setIParentId(null); | |
| 104 | + | |
| 105 | + service.create(dto); | |
| 106 | + | |
| 107 | + verify(moduleMapper, never()).findActiveFlagById(any()); | |
| 108 | + verify(moduleMapper, times(1)).insert(any(Module.class)); | |
| 109 | + } | |
| 110 | + | |
| 111 | + @Test | |
| 112 | + void mapperDuplicateKey_throws40020() { | |
| 113 | + CreateModuleDTO dto = baseDto(); | |
| 114 | + when(moduleMapper.insert(any(Module.class))) | |
| 115 | + .thenThrow(new DuplicateKeyException("uk_procedure_name")); | |
| 116 | + | |
| 117 | + assertThatThrownBy(() -> service.create(dto)) | |
| 118 | + .isInstanceOf(BizException.class) | |
| 119 | + .hasFieldOrPropertyWithValue("code", 40020); | |
| 120 | + } | |
| 121 | + | |
| 122 | + @Test | |
| 123 | + void usesAuthenticatedUserNoAsCreatedBy() { | |
| 124 | + SecurityContextHolder.getContext().setAuthentication( | |
| 125 | + new UsernamePasswordAuthenticationToken("ALICE", null, Collections.emptyList())); | |
| 126 | + CreateModuleDTO dto = baseDto(); | |
| 127 | + | |
| 128 | + service.create(dto); | |
| 129 | + | |
| 130 | + ArgumentCaptor<Module> captor = ArgumentCaptor.forClass(Module.class); | |
| 131 | + verify(moduleMapper).insert(captor.capture()); | |
| 132 | + assertThat(captor.getValue().getSCreatedBy()).isEqualTo("ALICE"); | |
| 133 | + } | |
| 134 | + | |
| 85 | 135 | private CreateModuleDTO baseDto() { |
| 86 | 136 | CreateModuleDTO dto = new CreateModuleDTO(); |
| 87 | 137 | dto.setSDisplayType("手机端"); | ... | ... |