1、线程池bean命名规范;2、菜单管理controller、service单元测试完善;3、已有controller单测替换mock static SecurityFrameworkUtils;

This commit is contained in:
gaoqr
2026-01-26 17:42:31 +08:00
parent b09892a349
commit 0d4700e225
12 changed files with 1008 additions and 279 deletions
@@ -0,0 +1,32 @@
package com.cf.imes.module.system.framework.executor.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* system服务线程池配置
*
* @author Gqr
* @since 2026/1/26 14:29
*/
@Configuration(proxyBeanMethods = false)
public class SystemThreadPoolConfiguration {
public static final String SYSTEM_PERMISSION_THREAD_POOL_TASK_EXECUTOR = "systemPermissionThreadPoolTaskExecutor";
@Bean("systemPermissionThreadPoolTaskExecutor")
public ThreadPoolTaskExecutor systemPermissionThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8); // 设置核心线程数
executor.setMaxPoolSize(8); // 设置最大线程数
executor.setKeepAliveSeconds(60); // 设置空闲时间
executor.setQueueCapacity(100); // 设置队列大小
executor.setThreadNamePrefix("system-permission-Executor-"); // 配置线程池的前缀
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 进行加载
executor.initialize();
return executor;
}
}
@@ -36,6 +36,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -53,6 +54,7 @@ import java.util.stream.IntStream;
import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertList;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;
import static com.cf.imes.module.system.framework.executor.config.SystemThreadPoolConfiguration.SYSTEM_PERMISSION_THREAD_POOL_TASK_EXECUTOR;
/**
* 菜单 Service 实现
@@ -80,6 +82,8 @@ public class MenuServiceImpl implements MenuService {
@Resource
private TransProperties transProperties;
@Resource(name = SYSTEM_PERMISSION_THREAD_POOL_TASK_EXECUTOR)
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
private static final String FIELD_CHARACTER = ":*:%s";
@@ -167,7 +171,7 @@ public class MenuServiceImpl implements MenuService {
* @param sourceType
*/
private void validateManageSourceTypeOperatePermission(Integer sourceType) {
if (!SecurityFrameworkUtils.isCfOrg() && sourceType.equals(MenuSourceTypeEnum.MANAGEMENT.getType())) {
if (!SecurityFrameworkUtils.isCfOrg() && MenuSourceTypeEnum.MANAGEMENT.getType().equals(sourceType)) {
throw new ServiceException(MANAGEMENT_MENU_OPERATION_PERMISSION_ERROR);
}
}
@@ -181,33 +185,32 @@ public class MenuServiceImpl implements MenuService {
*/
private void flushCacheWhenOperateMenu(Long menuId, String newPermission, String oldPermission) {
CompletableFuture.runAsync(() -> {
if (ObjectUtil.isNotNull(oldPermission)) {
// 移除 USER_ROLE_ID_LIST:*:旧的permission
String oldMenuPerPattern = String.format(String.valueOf(new StringBuffer(RedisKeyConstants.PERMISSION_MENU_ID_LIST).append(FIELD_CHARACTER)), oldPermission);
Long oldBatchDelPerNum = scanAndDelKeys(oldMenuPerPattern);
log.info("[updateMenu] 批量删除redis[{}]数量:{}", oldMenuPerPattern, oldBatchDelPerNum);
}
try {
if (ObjectUtil.isNotNull(oldPermission)) {
// 移除 USER_ROLE_ID_LIST:*:旧的permission
String oldMenuPerPattern = String.format(String.valueOf(new StringBuffer(RedisKeyConstants.PERMISSION_MENU_ID_LIST).append(FIELD_CHARACTER)), oldPermission);
Long oldBatchDelPerNum = scanAndDelKeys(oldMenuPerPattern);
log.info("[updateMenu] 批量删除redis[{}]数量:{}", oldMenuPerPattern, oldBatchDelPerNum);
}
if (ObjectUtil.isNotNull(newPermission)) {
// 移除 USER_ROLE_ID_LIST:*:新的permission
String newMenuPerPattern = String.format(String.valueOf(new StringBuffer(RedisKeyConstants.PERMISSION_MENU_ID_LIST).append(FIELD_CHARACTER)), newPermission);
Long newBatchDelPerNum = scanAndDelKeys(newMenuPerPattern);
log.info("[updateMenu] 批量删除redis[{}]数量:{}", newMenuPerPattern, newBatchDelPerNum);
}
if (ObjectUtil.isNotNull(newPermission)) {
// 移除 USER_ROLE_ID_LIST:*:新的permission
String newMenuPerPattern = String.format(String.valueOf(new StringBuffer(RedisKeyConstants.PERMISSION_MENU_ID_LIST).append(FIELD_CHARACTER)), newPermission);
Long newBatchDelPerNum = scanAndDelKeys(newMenuPerPattern);
log.info("[updateMenu] 批量删除redis[{}]数量:{}", newMenuPerPattern, newBatchDelPerNum);
}
if (ObjectUtil.isNotNull(menuId)) {
// 移除 MENU_ROLE_ID_LIST:*:menuId
String menuRolePattern = String.format(String.valueOf(new StringBuffer(RedisKeyConstants.MENU_ROLE_ID_LIST).append(FIELD_CHARACTER)), menuId);
Long batchDelRoleNum = scanAndDelKeys(menuRolePattern);
log.info("[deleteMenu] 批量删除redis[{}]数量:{}", menuRolePattern, batchDelRoleNum);
}
// 清空本地缓存
redisTemplate.convertAndSend(com.cf.imes.framework.redis.constants.RedisKeyConstants.PERMISSION_REFRESH, "");
}).exceptionally(e -> {
log.error("[deleteMenu] redis 清空PERMISSION_MENU_ID_LIST或message发送失败, topic:{}, 异常:{}", com.cf.imes.framework.redis.constants.RedisKeyConstants.PERMISSION_REFRESH, e);
return null;
});
// 清空本地缓存
redisTemplate.convertAndSend(com.cf.imes.framework.redis.constants.RedisKeyConstants.PERMISSION_REFRESH, "");
} catch (Exception e) {
log.error("[deleteMenu] redis 清空PERMISSION_MENU_ID_LIST或message发送失败, topic:{}, 异常:{}", com.cf.imes.framework.redis.constants.RedisKeyConstants.PERMISSION_REFRESH, e);
}
}, threadPoolTaskExecutor);
}
@@ -263,7 +266,7 @@ public class MenuServiceImpl implements MenuService {
@Override
public List<MenuDO> getMenuList(Collection<Long> ids) {
return menuMapper.selectBatchIds(ids);
return menuMapper.selectByIds(ids);
}
@Override
@@ -272,7 +275,7 @@ public class MenuServiceImpl implements MenuService {
if(CollUtil.isEmpty(ids)) {
return new ArrayList<>();
}
return menuMapper.selectBatchIds(ids);
return menuMapper.selectByIds(ids);
}
/**
@@ -300,8 +303,7 @@ public class MenuServiceImpl implements MenuService {
throw new ServiceException(MENU_PARENT_NOT_EXISTS);
}
// 父菜单必须是目录或者菜单类型
if (!MenuTypeEnum.DIR.getType().equals(menu.getType())
&& !MenuTypeEnum.MENU.getType().equals(menu.getType())) {
if (MenuTypeEnum.BUTTON.getType().equals(menu.getType())) {
throw new ServiceException(MENU_PARENT_NOT_DIR_OR_MENU);
}
}
@@ -407,7 +409,7 @@ public class MenuServiceImpl implements MenuService {
String src = item.getString("src");
String dst = item.getString("dst");
if (menuDO == null || !menuDO.getName().equals(UnicodeUtil.toString(src))) {
if (!menuDO.getName().equals(UnicodeUtil.toString(src))) {
continue;
}
@@ -2,6 +2,7 @@ package com.cf.imes.module.system.common;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
@@ -16,6 +17,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
* @author Gqr
* @since 2026/1/16 10:20
*/
@Slf4j
public class WithMockLoginUserExtension implements BeforeEachCallback, AfterEachCallback {
@Override
public void afterEach(ExtensionContext context) {
@@ -33,6 +35,8 @@ public class WithMockLoginUserExtension implements BeforeEachCallback, AfterEach
loginUser.setDeptId(ann.deptId());
loginUser.setNickname(ann.username());
loginUser.setIsSupAdmin(ann.isSuperAdmin());
loginUser.setUserType(ann.userType());
loginUser.setProductId(ann.productId());
} else {
return;
}
@@ -6,10 +6,12 @@ import com.cf.imes.framework.ip.core.service.dto.IPQueryDataRespDTO;
import com.cf.imes.framework.security.config.SecurityProperties;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
import com.cf.imes.framework.web.config.ChenfengWebAutoConfiguration;
import com.cf.imes.module.infra.api.logger.ApiErrorLogApi;
import com.cf.imes.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import com.cf.imes.module.system.common.WithMockLoginUserExtension;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginReqVO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginSmsCheckReqVO;
@@ -31,6 +33,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
import org.springframework.beans.factory.annotation.Autowired;
@@ -74,6 +77,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@WebMvcTest(controllers = AuthController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
@Import(ChenfengWebAutoConfiguration.class)
@ExtendWith(WithMockLoginUserExtension.class)
@TestPropertySource(properties = {
"spring.application.name=test-app"
})
@@ -283,136 +287,138 @@ class AuthControllerTest extends BaseWebUnitTest {
}
@Test
@WithMockLoginUser(userId = 1L, organId = 100L)
void testGetPermissionInfo_success() throws Exception {
try (MockedStatic<SecurityFrameworkUtils> utilities = mockStatic(SecurityFrameworkUtils.class)) {
utilities.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
utilities.when(SecurityFrameworkUtils::isManageEndPoint).thenReturn(false);
AdminUserDO user = new AdminUserDO();
user.setId(1L);
user.setOrganId(100L);
when(userService.getUser(1L)).thenReturn(user);
AdminUserDO user = new AdminUserDO();
user.setId(1L);
user.setOrganId(100L);
when(userService.getUser(1L)).thenReturn(user);
OrganizationDO organization = new OrganizationDO();
when(organService.validOrgan(100L)).thenReturn(organization);
OrganizationDO organization = new OrganizationDO();
when(organService.validOrgan(100L)).thenReturn(organization);
when(ipQueryService.serviceEnable()).thenReturn(false);
when(ipQueryService.serviceEnable()).thenReturn(false);
Set<Long> roleIds = new HashSet<>(Arrays.asList(10L, 20L));
when(permissionService.getUserRoleIdListByUserId(1L)).thenReturn(roleIds);
Set<Long> roleIds = new HashSet<>(Arrays.asList(10L, 20L));
when(permissionService.getUserRoleIdListByUserId(1L)).thenReturn(roleIds);
RoleDO role1 = new RoleDO();
role1.setId(10L);
role1.setStatus(1);
RoleDO role2 = new RoleDO();
role2.setId(20L);
role2.setStatus(1);
when(roleService.getRoleList1(roleIds))
.thenReturn(new ArrayList<>(Arrays.asList(role1, role2)));
RoleDO role1 = new RoleDO(); role1.setId(10L); role1.setStatus(1);
RoleDO role2 = new RoleDO(); role2.setId(20L); role2.setStatus(1);
when(roleService.getRoleList1(roleIds))
.thenReturn(new ArrayList<>(Arrays.asList(role1, role2)));
Set<Long> menuIds = new HashSet<>(Arrays.asList(1000L, 2000L));
when(permissionService.getRoleMenuListByRoleId2(anySet(), eq(100L))).thenReturn(menuIds);
Set<Long> menuIds = new HashSet<>(Arrays.asList(1000L, 2000L));
when(permissionService.getRoleMenuListByRoleId2(anySet(), eq(100L))).thenReturn(menuIds);
MenuDO menu1 = new MenuDO();
menu1.setId(1000L);
menu1.setStatus(1);
MenuDO menu2 = new MenuDO();
menu2.setId(2000L);
menu2.setStatus(1);
when(menuService.getCustomEndPointMenuList(menuIds))
.thenReturn(new ArrayList<>(Arrays.asList(menu1, menu2)));
MenuDO menu1 = new MenuDO(); menu1.setId(1000L); menu1.setStatus(1);
MenuDO menu2 = new MenuDO(); menu2.setId(2000L); menu2.setStatus(1);
when(menuService.getCustomEndPointMenuList(menuIds))
.thenReturn(new ArrayList<>(Arrays.asList(menu1, menu2)));
mockMvc.perform(get("/admin-api/system/auth/get-permission-info"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").exists());
mockMvc.perform(get("/admin-api/system/auth/get-permission-info"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").exists());
// 验证调用顺序/次数(可选)
verify(userService, times(1)).getUser(1L);
verify(organService, times(1)).validOrgan(100L);
verify(roleService, times(1)).getRoleList1(roleIds);
verify(menuService, times(1)).getCustomEndPointMenuList(menuIds);
}
// 验证调用顺序/次数(可选)
verify(userService, times(1)).getUser(1L);
verify(organService, times(1)).validOrgan(100L);
verify(roleService, times(1)).getRoleList1(roleIds);
verify(menuService, times(1)).getCustomEndPointMenuList(menuIds);
}
@Test
@WithMockLoginUser(userId = 1L, organId = 100L, userType = 2)
void testGetPermissionInfo_success_branch() throws Exception {
try (MockedStatic<SecurityFrameworkUtils> utilities = mockStatic(SecurityFrameworkUtils.class)) {
utilities.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
utilities.when(SecurityFrameworkUtils::isManageEndPoint).thenReturn(true);
AdminUserDO user = new AdminUserDO();
user.setId(1L);
user.setOrganId(100L);
when(userService.getUser(1L)).thenReturn(user);
AdminUserDO user = new AdminUserDO();
user.setId(1L);
user.setOrganId(100L);
when(userService.getUser(1L)).thenReturn(user);
OrganizationDO organization = new OrganizationDO();
when(organService.validOrgan(100L)).thenReturn(organization);
OrganizationDO organization = new OrganizationDO();
when(organService.validOrgan(100L)).thenReturn(organization);
IPQueryDataRespDTO ipResp = new IPQueryDataRespDTO();
ipResp.setProv("浙江");
ipResp.setCity("杭州");
ipResp.setArea("西湖");
when(ipQueryService.serviceEnable()).thenReturn(true);
when(ipQueryService.querySource(anyString())).thenReturn(ipResp);
IPQueryDataRespDTO ipResp = new IPQueryDataRespDTO();
ipResp.setProv("浙江");
ipResp.setCity("杭州");
ipResp.setArea("西湖");
when(ipQueryService.serviceEnable()).thenReturn(true);
when(ipQueryService.querySource(anyString())).thenReturn(ipResp);
Set<Long> roleIds = new HashSet<>(Arrays.asList(10L, 20L));
when(permissionService.getUserRoleIdListByUserId(1L)).thenReturn(roleIds);
Set<Long> roleIds = new HashSet<>(Arrays.asList(10L, 20L));
when(permissionService.getUserRoleIdListByUserId(1L)).thenReturn(roleIds);
RoleDO role1 = new RoleDO();
role1.setId(10L);
role1.setStatus(1);
RoleDO role2 = new RoleDO();
role2.setId(20L);
role2.setStatus(1);
when(roleService.getRoleList1(roleIds))
.thenReturn(new ArrayList<>(Arrays.asList(role1, role2)));
RoleDO role1 = new RoleDO(); role1.setId(10L); role1.setStatus(1);
RoleDO role2 = new RoleDO(); role2.setId(20L); role2.setStatus(1);
when(roleService.getRoleList1(roleIds))
.thenReturn(new ArrayList<>(Arrays.asList(role1, role2)));
Set<Long> menuIds = new HashSet<>(Arrays.asList(1000L, 2000L));
when(permissionService.getRoleMenuListByRoleId2(anySet(), eq(100L))).thenReturn(menuIds);
Set<Long> menuIds = new HashSet<>(Arrays.asList(1000L, 2000L));
when(permissionService.getRoleMenuListByRoleId2(anySet(), eq(100L))).thenReturn(menuIds);
MenuDO menu1 = new MenuDO();
menu1.setId(1000L);
menu1.setStatus(1);
MenuDO menu2 = new MenuDO();
menu2.setId(2000L);
menu2.setStatus(1);
when(menuService.getManageEndPointMenuList(menuIds))
.thenReturn(new ArrayList<>(Arrays.asList(menu1, menu2)));
MenuDO menu1 = new MenuDO(); menu1.setId(1000L); menu1.setStatus(1);
MenuDO menu2 = new MenuDO(); menu2.setId(2000L); menu2.setStatus(1);
when(menuService.getManageEndPointMenuList(menuIds))
.thenReturn(new ArrayList<>(Arrays.asList(menu1, menu2)));
mockMvc.perform(get("/admin-api/system/auth/get-permission-info"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").exists());
mockMvc.perform(get("/admin-api/system/auth/get-permission-info"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").exists());
// 验证调用顺序/次数(可选)
verify(userService, times(1)).getUser(1L);
verify(organService, times(1)).validOrgan(100L);
verify(ipQueryService, times(1)).querySource(anyString());
verify(roleService, times(1)).getRoleList1(roleIds);
verify(menuService, times(1)).getManageEndPointMenuList(menuIds);
}
// 验证调用顺序/次数(可选)
verify(userService, times(1)).getUser(1L);
verify(organService, times(1)).validOrgan(100L);
verify(ipQueryService, times(1)).querySource(anyString());
verify(roleService, times(1)).getRoleList1(roleIds);
verify(menuService, times(1)).getManageEndPointMenuList(menuIds);
}
@Test
@WithMockLoginUser(userId = 1L, organId = 100L)
void testGetPermissionInfo_success_roleEmpty() throws Exception {
try (MockedStatic<SecurityFrameworkUtils> utilities = mockStatic(SecurityFrameworkUtils.class)) {
utilities.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
utilities.when(SecurityFrameworkUtils::isManageEndPoint).thenReturn(true);
AdminUserDO user = new AdminUserDO();
user.setId(1L);
user.setOrganId(100L);
when(userService.getUser(1L)).thenReturn(user);
AdminUserDO user = new AdminUserDO();
user.setId(1L);
user.setOrganId(100L);
when(userService.getUser(1L)).thenReturn(user);
OrganizationDO organization = new OrganizationDO();
when(organService.validOrgan(100L)).thenReturn(organization);
OrganizationDO organization = new OrganizationDO();
when(organService.validOrgan(100L)).thenReturn(organization);
when(ipQueryService.serviceEnable()).thenReturn(false);
when(ipQueryService.serviceEnable()).thenReturn(false);
Set<Long> roleIds = new HashSet<>();
when(permissionService.getUserRoleIdListByUserId(1L)).thenReturn(roleIds);
Set<Long> roleIds = new HashSet<>();
when(permissionService.getUserRoleIdListByUserId(1L)).thenReturn(roleIds);
mockMvc.perform(get("/admin-api/system/auth/get-permission-info"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.roles").isEmpty());
mockMvc.perform(get("/admin-api/system/auth/get-permission-info"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.roles").isEmpty());
// 验证调用顺序/次数(可选)
verify(userService, times(1)).getUser(1L);
verify(organService, times(1)).validOrgan(100L);
verify(ipQueryService, never()).querySource(anyString());
verify(roleService, never()).getRoleList1(roleIds);
verify(menuService, never()).getManageEndPointMenuList(anySet());
}
// 验证调用顺序/次数(可选)
verify(userService, times(1)).getUser(1L);
verify(organService, times(1)).validOrgan(100L);
verify(ipQueryService, never()).querySource(anyString());
verify(roleService, never()).getRoleList1(roleIds);
verify(menuService, never()).getManageEndPointMenuList(anySet());
}
@Test
@WithMockLoginUser(userId = 1L)
void testGetPermissionInfo_userNull() throws Exception {
try (MockedStatic<SecurityFrameworkUtils> utilities = mockStatic(SecurityFrameworkUtils.class)) {
utilities.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
when(userService.getUser(1L)).thenReturn(null);
mockMvc.perform(get("/admin-api/system/auth/get-permission-info"))
@@ -420,7 +426,6 @@ class AuthControllerTest extends BaseWebUnitTest {
.andExpect(jsonPath("$.data").isEmpty()); // 返回 null
verify(userService, times(1)).getUser(1L);
}
}
@Test
@@ -2,6 +2,7 @@ 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.test.core.ut.BaseWebUnitTest;
import com.cf.imes.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO;
import com.cf.imes.module.system.controller.admin.dict.vo.data.DictDataSimpleRespVO;
import com.cf.imes.module.system.controller.admin.dict.vo.data.DictDataTransReqVO;
@@ -37,7 +38,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @since 2026/1/14 15:38
*/
@WebMvcTest(controllers = DictDataController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
class DictDataControllerTest {
class DictDataControllerTest extends BaseWebUnitTest {
@Autowired
private MockMvc mockMvc;
@@ -3,6 +3,7 @@ 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.framework.test.core.ut.BaseWebUnitTest;
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;
@@ -42,7 +43,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @since 2026/1/14 17:25
*/
@WebMvcTest(controllers = DictTypeController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
public class DictTypeControllerTest {
class DictTypeControllerTest extends BaseWebUnitTest {
@Autowired
private MockMvc mockMvc;
@@ -3,7 +3,9 @@ package com.cf.imes.module.system.controller.admin.funds.products;
import com.cf.imes.framework.common.pojo.PageParam;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
import com.cf.imes.module.system.common.WithMockLoginUserExtension;
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.products.vo.product.ProductSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
@@ -11,6 +13,7 @@ import com.cf.imes.module.system.enums.products.ProductStatusEnum;
import com.cf.imes.module.system.service.funds.products.ProductsService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
@@ -41,6 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @since 2025/10/14 11:16
*/
@WebMvcTest(controllers = ProductsController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
@ExtendWith(WithMockLoginUserExtension.class)
class ProductsControllerTest extends BaseWebUnitTest {
@Autowired
private MockMvc mockMvc;
@@ -164,6 +168,7 @@ class ProductsControllerTest extends BaseWebUnitTest {
}
@Test
@WithMockLoginUser(userType = 2)
void testGetAvailableProductsPage() throws Exception {
ProductPageReqVO reqVO = new ProductPageReqVO();
PageResult<ProductsDO> mockPage = new PageResult<>();
@@ -171,21 +176,17 @@ class ProductsControllerTest extends BaseWebUnitTest {
mockPage.setList(List.of(new ProductsDO().setId(1L).setProductName("已上架产品")));
when(productsService.getPage(any())).thenReturn(mockPage);
// mock 管理端标识
try (var ignored = mockStatic(SecurityFrameworkUtils.class)) {
when(SecurityFrameworkUtils.isManageEndPoint()).thenReturn(true);
mockMvc.perform(get("/system/products/available")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.list[0].productName").value("已上架产品"));
mockMvc.perform(get("/system/products/available")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.list[0].productName").value("已上架产品"));
verify(productsService, times(1)).getPage(any());
}
verify(productsService, times(1)).getPage(any());
}
@Test
@WithMockLoginUser(productId = 123L)
void testGetAvailableProductsPage_nonManager() throws Exception {
ProductPageReqVO reqVO = new ProductPageReqVO();
@@ -1,15 +1,15 @@
package com.cf.imes.module.system.controller.admin.funds.purchase;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
import com.cf.imes.module.system.common.WithMockLoginUserExtension;
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.PurchaseRecordPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.PurchaseRecordRespVO;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
@@ -39,6 +39,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
controllers = PurchaseController.class,
excludeAutoConfiguration = SecurityAutoConfiguration.class
)
@ExtendWith(WithMockLoginUserExtension.class)
class PurchaseControllerTest extends BaseWebUnitTest {
@Autowired
private MockMvc mockMvc;
@@ -50,13 +51,8 @@ class PurchaseControllerTest extends BaseWebUnitTest {
* 非管理端:获取购买记录分页
*/
@Test
@WithMockLoginUser(organId = 1L)
void testGetPurchaseRecord_nonManage() throws Exception {
try (MockedStatic<SecurityFrameworkUtils> mocked = Mockito.mockStatic(SecurityFrameworkUtils.class)) {
// mock 当前为非管理端
mocked.when(SecurityFrameworkUtils::isManageEndPoint).thenReturn(false);
mocked.when(SecurityFrameworkUtils::getUserOrganId).thenReturn(1L);
// mock service 返回
PurchaseRecordRespVO respVO = new PurchaseRecordRespVO();
respVO.setId(1L);
@@ -84,18 +80,15 @@ class PurchaseControllerTest extends BaseWebUnitTest {
.getPurchaseRecord(captor.capture());
assertEquals(1L, captor.getValue().getOrganId());
}
}
/**
* 管理端:获取购买记录分页
*/
@Test
@WithMockLoginUser(userType = 2)
void testGetPurchaseRecord_manage() throws Exception {
try (MockedStatic<SecurityFrameworkUtils> mocked = Mockito.mockStatic(SecurityFrameworkUtils.class)) {
mocked.when(SecurityFrameworkUtils::isManageEndPoint).thenReturn(true);
PageResult<PurchaseRecordRespVO> pageResult = new PageResult<>();
pageResult.setTotal(0L);
pageResult.setList(Collections.emptyList());
@@ -110,64 +103,54 @@ class PurchaseControllerTest extends BaseWebUnitTest {
verify(purchaseService, times(1))
.getPurchaseRecord(any());
}
}
/**
* 非管理端:导出购买记录
*/
@Test
@WithMockLoginUser(organId = 1L)
void testExportPurchaseRecord_nonManage() throws Exception {
try (MockedStatic<SecurityFrameworkUtils> mocked = Mockito.mockStatic(SecurityFrameworkUtils.class)) {
PurchaseRecordRespVO respVO = new PurchaseRecordRespVO();
respVO.setId(1L);
respVO.setOrganId(1L);
mocked.when(SecurityFrameworkUtils::isManageEndPoint).thenReturn(false);
mocked.when(SecurityFrameworkUtils::getUserOrganId).thenReturn(1L);
PageResult<PurchaseRecordRespVO> pageResult = new PageResult<>();
pageResult.setTotal(1L);
pageResult.setList(List.of(respVO));
PurchaseRecordRespVO respVO = new PurchaseRecordRespVO();
respVO.setId(1L);
respVO.setOrganId(1L);
when(purchaseService.getPurchaseRecord(any()))
.thenReturn(pageResult);
PageResult<PurchaseRecordRespVO> pageResult = new PageResult<>();
pageResult.setTotal(1L);
pageResult.setList(List.of(respVO));
mockMvc.perform(get("/system/purchase/export")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
when(purchaseService.getPurchaseRecord(any()))
.thenReturn(pageResult);
mockMvc.perform(get("/system/purchase/export")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(purchaseService, times(1))
.getPurchaseRecord(any());
}
verify(purchaseService, times(1))
.getPurchaseRecord(any());
}
//
/**
* 管理端:导出购买记录
*/
@Test
@WithMockLoginUser(userType = 2)
void testExportPurchaseRecord_manage() throws Exception {
try (MockedStatic<SecurityFrameworkUtils> mocked = Mockito.mockStatic(SecurityFrameworkUtils.class)) {
PurchaseRecordRespVO respVO = new PurchaseRecordRespVO();
respVO.setId(1L);
mocked.when(SecurityFrameworkUtils::isManageEndPoint).thenReturn(true);
PageResult<PurchaseRecordRespVO> pageResult = new PageResult<>();
pageResult.setTotal(1L);
pageResult.setList(List.of(respVO));
PurchaseRecordRespVO respVO = new PurchaseRecordRespVO();
respVO.setId(1L);
when(purchaseService.getPurchaseRecord(any()))
.thenReturn(pageResult);
PageResult<PurchaseRecordRespVO> pageResult = new PageResult<>();
pageResult.setTotal(1L);
pageResult.setList(List.of(respVO));
mockMvc.perform(get("/system/purchase/export")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
when(purchaseService.getPurchaseRecord(any()))
.thenReturn(pageResult);
mockMvc.perform(get("/system/purchase/export")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(purchaseService, times(1))
.getPurchaseRecord(any());
}
verify(purchaseService, times(1))
.getPurchaseRecord(any());
}
}
@@ -0,0 +1,340 @@
package com.cf.imes.module.system.controller.admin.permission;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseWebUnitTest;
import com.cf.imes.framework.web.config.ChenfengWebAutoConfiguration;
import com.cf.imes.module.infra.api.logger.ApiErrorLogApi;
import com.cf.imes.module.system.common.WithMockLoginUserExtension;
import com.cf.imes.module.system.controller.admin.permission.vo.menu.*;
import com.cf.imes.module.system.dal.dataobject.permission.MenuDO;
import com.cf.imes.module.system.dal.dataobject.permission.RoleDO;
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
import com.cf.imes.module.system.enums.permission.MenuSourceTypeEnum;
import com.cf.imes.module.system.enums.permission.MenuTypeEnum;
import com.cf.imes.module.system.service.permission.MenuService;
import com.cf.imes.module.system.service.permission.PermissionService;
import com.cf.imes.module.system.service.permission.RoleService;
import com.cf.imes.module.system.service.user.AdminUserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
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.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import java.util.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* 菜单管理单元测试
*
* @author Gqr
* @since 2026/1/26 16:40
*/
@WebMvcTest(controllers = MenuController.class, excludeAutoConfiguration = SecurityAutoConfiguration.class)
@ExtendWith(WithMockLoginUserExtension.class)
@Import(ChenfengWebAutoConfiguration.class)
@TestPropertySource(properties = {
"spring.application.name=test-app"
})
class MenuControllerTest extends BaseWebUnitTest {
@Autowired
private MockMvc mockMvc;
@MockitoBean
private MenuService menuService;
@MockitoBean
private PermissionService permissionService;
@MockitoBean
private AdminUserService userService;
@MockitoBean
private RoleService roleService;
@Autowired
private ObjectMapper objectMapper;
@MockitoBean
private ApiErrorLogApi apiErrorLogApi;
@Test
void createMenu_success() throws Exception {
MenuSaveVO reqVO = new MenuSaveVO();
reqVO.setName("新增菜单");
reqVO.setParentId(0L);
reqVO.setType(MenuTypeEnum.MENU.getType());
reqVO.setSort(1);
reqVO.setParentId(MenuDO.ID_ROOT);
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setSourceType(MenuSourceTypeEnum.PRODUCTION.getType());
when(menuService.createMenu(any(MenuSaveVO.class)))
.thenReturn(100L);
mockMvc.perform(post("/admin-api/system/menu/create")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").value(100L));
}
@Test
void updateMenu_success() throws Exception {
MenuSaveVO reqVO = new MenuSaveVO();
reqVO.setId(1L);
reqVO.setName("更新菜单");
reqVO.setType(MenuTypeEnum.MENU.getType());
reqVO.setSort(1);
reqVO.setParentId(MenuDO.ID_ROOT);
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setSourceType(MenuSourceTypeEnum.PRODUCTION.getType());
mockMvc.perform(put("/admin-api/system/menu/update")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").value(true));
verify(menuService).updateMenu(any(MenuSaveVO.class));
}
@Test
void deleteMenu_success() throws Exception {
mockMvc.perform(delete("/admin-api/system/menu/delete")
.param("id", "1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").value(true));
verify(menuService).deleteMenu(1L);
}
@Test
@WithMockLoginUser(userId = 1L, organId = 100L)
void getCustomMenuList_success() throws Exception {
// 准备模拟数据
List<MenuDO> menuList = Arrays.asList(createMenuDO(1L, CommonStatusEnum.ENABLE.getStatus()));
AdminUserDO user = new AdminUserDO();
user.setId(1L);
Set<Long> roleIds = new HashSet<>();
roleIds.add(1L);
List<RoleDO> roles = Arrays.asList(createRoleDO(1L, CommonStatusEnum.ENABLE.getStatus()));
Set<Long> menuIds = new HashSet<>();
menuIds.add(1L);
when(userService.getUser(1L)).thenReturn(user);
when(permissionService.getUserRoleIdListByUserId(1L)).thenReturn(roleIds);
when(roleService.getRoleList1(roleIds)).thenReturn(roles);
when(permissionService.getRoleMenuListByRoleId2(any(Set.class), eq(100L))).thenReturn(menuIds);
when(menuService.getCustomEndPointMenuList(menuIds)).thenReturn(menuList);
mockMvc.perform(get("/admin-api/system/menu/custom/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").isArray());
verify(userService).getUser(1L);
verify(permissionService).getUserRoleIdListByUserId(1L);
verify(roleService).getRoleList1(roleIds);
verify(permissionService).getRoleMenuListByRoleId2(any(Set.class), eq(100L));
verify(menuService).getCustomEndPointMenuList(menuIds);
}
@Test
@WithMockLoginUser(userId = 1L, organId = 100L, isSuperAdmin = true)
void getMenuList_superAdmin_success() throws Exception {
// 准备模拟数据
List<MenuDO> menuList = Arrays.asList(createMenuDO(1L, CommonStatusEnum.ENABLE.getStatus()));
when(menuService.getMenuList(any(MenuListReqVO.class))).thenReturn(menuList);
mockMvc.perform(get("/admin-api/system/menu/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").isArray());
verify(menuService).getMenuList(any(MenuListReqVO.class));
}
@Test
@WithMockLoginUser(userId = 1L, organId = 100L)
void getMenuList_notsuperAdmin_getUserNull() throws Exception {
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
when(userService.getUser(loginUserId)).thenReturn(null);
mockMvc.perform(get("/admin-api/system/menu/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").isEmpty());
}
@Test
@WithMockLoginUser(userId = 1L, organId = 100L)
void getMenuList_notsuperAdmin_getRolesEmpty() throws Exception {
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
when(userService.getUser(loginUserId)).thenReturn(new AdminUserDO());
when(permissionService.getUserRoleIdListByUserId(loginUserId)).thenReturn(null);
mockMvc.perform(get("/admin-api/system/menu/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").isEmpty());
}
@Test
@WithMockLoginUser(userId = 1L, organId = 100L)
void getMenuList_normalUser_success() throws Exception {
// 准备模拟数据
List<MenuDO> menuList = Arrays.asList(createMenuDO(1L, CommonStatusEnum.ENABLE.getStatus()));
AdminUserDO user = new AdminUserDO();
user.setId(1L);
Set<Long> roleIds = new HashSet<>();
roleIds.add(1L);
List<RoleDO> roles = Arrays.asList(createRoleDO(1L, CommonStatusEnum.ENABLE.getStatus()));
Set<Long> menuIds = new HashSet<>();
menuIds.add(1L);
when(userService.getUser(1L)).thenReturn(user);
when(permissionService.getUserRoleIdListByUserId(1L)).thenReturn(roleIds);
when(roleService.getRoleList1(roleIds)).thenReturn(roles);
when(permissionService.getRoleMenuListByRoleId2(any(Set.class), eq(100L))).thenReturn(menuIds);
when(menuService.getMenuList1(menuIds)).thenReturn(menuList);
mockMvc.perform(get("/admin-api/system/menu/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").isArray());
verify(userService).getUser(1L);
verify(permissionService).getUserRoleIdListByUserId(1L);
verify(roleService).getRoleList1(roleIds);
verify(permissionService).getRoleMenuListByRoleId2(any(Set.class), eq(100L));
verify(menuService).getMenuList1(menuIds);
}
@Test
void getMenuList_noLoginUser_failure() throws Exception {
mockMvc.perform(get("/admin-api/system/menu/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(GlobalErrorCodeConstants.UNAUTHORIZED.getCode()));
}
@Test
void getCustomMenuList_noLoginUser_failure() throws Exception {
mockMvc.perform(get("/admin-api/system/menu/custom/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(GlobalErrorCodeConstants.UNAUTHORIZED.getCode()));
}
@Test
@WithMockLoginUser
void getCustomMenuList_getUserNull() throws Exception {
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
when(userService.getUser(loginUserId)).thenReturn(null);
mockMvc.perform(get("/admin-api/system/menu/custom/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").isEmpty());
}
@Test
@WithMockLoginUser
void getCustomMenuList_getRolesEmpty() throws Exception {
Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
when(userService.getUser(loginUserId)).thenReturn(new AdminUserDO());
when(permissionService.getUserRoleIdListByUserId(loginUserId)).thenReturn(null);
mockMvc.perform(get("/admin-api/system/menu/custom/list"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").isEmpty());
}
@Test
void getSimpleMenuList_success() throws Exception {
List<MenuDO> menuList = Arrays.asList(createMenuDO(1L, CommonStatusEnum.ENABLE.getStatus()));
when(menuService.getMenuListByOrgan(any(MenuListReqVO.class))).thenReturn(menuList);
mockMvc.perform(get("/admin-api/system/menu/list-all-simple"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").isArray());
verify(menuService).getMenuListByOrgan(any(MenuListReqVO.class));
}
@Test
void getMenu_success() throws Exception {
MenuDO menuDO = createMenuDO(1L, CommonStatusEnum.ENABLE.getStatus());
when(menuService.getMenu(1L)).thenReturn(menuDO);
mockMvc.perform(get("/admin-api/system/menu/get")
.param("id", "1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data.id").value(1L));
verify(menuService).getMenu(1L);
}
@Test
void trans_success() throws Exception {
MenuTransReqVO reqVO = new MenuTransReqVO();
reqVO.setTargetLanguage("en");
mockMvc.perform(post("/admin-api/system/menu/trans")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reqVO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").value(true));
verify(menuService).trans(any(MenuTransReqVO.class));
}
// 辅助方法:创建MenuDO实例
private MenuDO createMenuDO(Long id, Integer status) {
MenuDO menuDO = new MenuDO();
menuDO.setId(id);
menuDO.setStatus(status);
menuDO.setName("测试菜单");
menuDO.setSort(0);
return menuDO;
}
// 辅助方法:创建RoleDO实例
private RoleDO createRoleDO(Long id, Integer status) {
RoleDO roleDO = new RoleDO();
roleDO.setId(id);
roleDO.setStatus(status);
return roleDO;
}
}
@@ -1,74 +1,189 @@
package com.cf.imes.module.system.service.permission;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.test.core.ut.BaseDbUnitTest;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.security.test.WithMockLoginUser;
import com.cf.imes.framework.test.core.ut.BaseMockitoUnitTest;
import com.cf.imes.module.system.common.WithMockLoginUserExtension;
import com.cf.imes.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
import com.cf.imes.module.system.controller.admin.permission.vo.menu.MenuSaveVO;
import com.cf.imes.module.system.controller.admin.permission.vo.menu.MenuTransReqVO;
import com.cf.imes.module.system.dal.dataobject.permission.MenuDO;
import com.cf.imes.module.system.dal.dataobject.permission.MenuI18nDO;
import com.cf.imes.module.system.dal.mysql.permission.MenuI18nMapper;
import com.cf.imes.module.system.dal.mysql.permission.MenuMapper;
import com.cf.imes.module.system.enums.common.LanguageEnum;
import com.cf.imes.module.system.enums.permission.MenuSourceTypeEnum;
import com.cf.imes.module.system.enums.permission.MenuTypeEnum;
import com.cf.imes.module.system.framework.trans.config.TransApi;
import com.cf.imes.module.system.framework.trans.config.TransProperties;
import com.cf.imes.module.system.service.organ.OrganService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.cf.imes.framework.common.util.collection.SetUtils.asSet;
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 org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@Import(MenuServiceImpl.class)
public class MenuServiceImplTest extends BaseDbUnitTest {
@ExtendWith(WithMockLoginUserExtension.class)
class MenuServiceImplTest extends BaseMockitoUnitTest {
@Resource
@InjectMocks
private MenuServiceImpl menuService;
@Resource
@Mock
private MenuMapper menuMapper;
@MockBean
@Mock
private PermissionService permissionService;
@MockBean
private OrganService tenantService;
@Mock
private OrganService organService;
@Mock
private RedisTemplate redisTemplate;
@Mock
private Cursor<String> cursor;
@Mock
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Mock
private MenuI18nMapper menuI18nMapper;
@Mock
private TransProperties transProperties;
@Test
public void testCreateMenu_success() {
@WithMockLoginUser(organId = 1L)
void testCreateMenu_success() {
// mock 数据(构造父菜单)
MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU,
"parent", 0L);
menuMapper.insert(menuDO);
Long parentId = menuDO.getId();
when(menuMapper.selectById(parentId)).thenReturn(menuDO);
// 校验自己
when(menuMapper.selectByParentIdAndNameAndSourceType(any(), any(), any())).thenReturn(null);
// 模拟 Mapper 插入时生成 ID
doAnswer(invocation -> {
MenuDO mdo = invocation.getArgument(0);
mdo.setId(100L); // 模拟自增主键
return null;
}).when(menuMapper).insert(any(MenuDO.class));
// 准备参数
MenuSaveVO reqVO = randomPojo(MenuSaveVO.class, o -> {
o.setParentId(parentId);
o.setName("testSonName");
o.setType(MenuTypeEnum.MENU.getType());
o.setType(MenuTypeEnum.BUTTON.getType());
}).setId(null); // 防止 id 被赋值
// redis mock
when(redisTemplate.scan(any())).thenReturn(cursor);
when(cursor.hasNext()).thenReturn(true, false);
// mock executor
doAnswer((InvocationOnMock invocation) -> {
((Runnable) invocation.getArguments()[0]).run();
return null;
}).when(threadPoolTaskExecutor).execute(any(Runnable.class));
Long menuId = menuService.createMenu(reqVO);
// 校验记录的属性是否正确
MenuDO dbMenu = menuMapper.selectById(menuId);
assertPojoEquals(reqVO, dbMenu, "id");
// 断言
assertEquals(100L, menuId);
verify(redisTemplate, times(1)).convertAndSend(com.cf.imes.framework.redis.constants.RedisKeyConstants.PERMISSION_REFRESH, "");
verify(redisTemplate, times(2)).scan(any());
verify(menuMapper).insert(argThat((MenuDO menuArg) ->
ObjectUtil.equals(menuArg.getName(), reqVO.getName())
&& ObjectUtil.equals(menuArg.getPermission(), reqVO.getPermission())
&& ObjectUtil.equals(menuArg.getType(), reqVO.getType())
&& ObjectUtil.equals(menuArg.getSort(), reqVO.getSort())
&& ObjectUtil.equals(menuArg.getParentId(), reqVO.getParentId())
&& ObjectUtil.equals("", menuArg.getPath())
&& ObjectUtil.equals("", menuArg.getIcon())
&& ObjectUtil.equals("", menuArg.getComponent())
&& ObjectUtil.equals("", menuArg.getComponentName())
&& ObjectUtil.equals(menuArg.getStatus(), reqVO.getStatus())
&& ObjectUtil.equals(menuArg.getVisible(), reqVO.getVisible())
&& ObjectUtil.equals(menuArg.getKeepAlive(), reqVO.getKeepAlive())
&& ObjectUtil.equals(menuArg.getAlwaysShow(), reqVO.getAlwaysShow())
&& ObjectUtil.equals(menuArg.getDescription(), reqVO.getDescription())
&& ObjectUtil.equals(menuArg.getSourceType(), reqVO.getSourceType())
));
}
@Test
public void testUpdateMenu_success() {
@WithMockLoginUser
void testCreateMenu_fail_sourceTypePermissionError() {
// mock 数据(构造父菜单)
MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU,
"parent", 0L);
Long parentId = menuDO.getId();
when(menuMapper.selectById(parentId)).thenReturn(menuDO);
// 校验自己
when(menuMapper.selectByParentIdAndNameAndSourceType(any(), any(), any())).thenReturn(null);
// 准备参数
MenuSaveVO reqVO = randomPojo(MenuSaveVO.class, o -> {
o.setParentId(parentId);
o.setSourceType(MenuSourceTypeEnum.MANAGEMENT.getType());
}).setId(null); // 防止 id 被赋值
assertServiceException(() -> menuService.createMenu(reqVO), MANAGEMENT_MENU_OPERATION_PERMISSION_ERROR);
}
@Test
@WithMockLoginUser
void testUpdateMenu_success() {
// 校验父级
MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU,
"parent", 0L);
// mock 数据(构造父子菜单)
MenuDO sonMenuDO = createParentAndSonMenu();
MenuDO sonMenuDO = buildMenuDO(MenuTypeEnum.MENU, "testSonName",
menuDO.getParentId());
when(menuMapper.selectById(any())).thenReturn(sonMenuDO).thenReturn(menuDO);
when(menuMapper.selectByParentIdAndNameAndSourceType(any(), any(), any())).thenReturn(sonMenuDO);
Long sonId = sonMenuDO.getId();
// 准备参数
MenuSaveVO reqVO = randomPojo(MenuSaveVO.class, o -> {
@@ -76,17 +191,67 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
o.setName("testSonName"); // 修改名字
o.setParentId(sonMenuDO.getParentId());
o.setType(MenuTypeEnum.MENU.getType());
o.setPermission(null);
});
// redis mock
when(redisTemplate.scan(any())).thenReturn(cursor);
when(cursor.hasNext()).thenReturn(true, false);
// mock executor
doAnswer((InvocationOnMock invocation) -> {
((Runnable) invocation.getArguments()[0]).run();
return null;
}).when(threadPoolTaskExecutor).execute(any(Runnable.class));
// 调用
menuService.updateMenu(reqVO);
// 校验记录的属性是否正确
verify(menuMapper, times(1)).updateById(any(MenuDO.class));
verify(redisTemplate, times(2)).scan(any());
verify(redisTemplate, times(1)).convertAndSend(com.cf.imes.framework.redis.constants.RedisKeyConstants.PERMISSION_REFRESH, "");
}
@Test
@WithMockLoginUser
void testUpdateMenu_success_flushCache() {
// 校验父级
MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU,
"parent", 0L);
// mock 数据(构造父子菜单)
MenuDO sonMenuDO = buildMenuDO(MenuTypeEnum.MENU, "testSonName",
menuDO.getParentId());
// same permission
sonMenuDO.setPermission("permission");
when(menuMapper.selectById(any())).thenReturn(sonMenuDO).thenReturn(menuDO);
when(menuMapper.selectByParentIdAndNameAndSourceType(any(), any(), any())).thenReturn(sonMenuDO);
Long sonId = sonMenuDO.getId();
// 准备参数
MenuSaveVO reqVO = randomPojo(MenuSaveVO.class, o -> {
o.setId(sonId);
o.setName("testSonName"); // 修改名字
o.setParentId(sonMenuDO.getParentId());
o.setType(MenuTypeEnum.MENU.getType());
// same permission
o.setPermission("permission");
});
// 调用
menuService.updateMenu(reqVO);
// 校验记录的属性是否正确
MenuDO dbMenu = menuMapper.selectById(sonId);
assertPojoEquals(reqVO, dbMenu);
verify(menuMapper, times(1)).updateById(any(MenuDO.class));
verify(redisTemplate, never()).scan(any());
verify(redisTemplate, never()).convertAndSend(anyString(), anyString());
}
@Test
public void testUpdateMenu_sonIdNotExist() {
void testUpdateMenu_sonIdNotExist() {
// 准备参数
MenuSaveVO reqVO = randomPojo(MenuSaveVO.class);
// 调用,并断言异常
@@ -94,46 +259,44 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testDeleteMenu_success() {
@WithMockLoginUser
void testDeleteMenu_success() {
// mock 数据
MenuDO menuDO = randomPojo(MenuDO.class);
menuMapper.insert(menuDO);
// 准备参数
Long id = menuDO.getId();
when(menuMapper.selectCountByParentId(id)).thenReturn(0L);
when(menuMapper.selectById(id)).thenReturn(menuDO);
// 调用
menuService.deleteMenu(id);
// 断言
MenuDO dbMenuDO = menuMapper.selectById(id);
assertNull(dbMenuDO);
verify(permissionService).processMenuDeleted(id);
verify(menuMapper, times(1)).deleteById(id);
verify(permissionService, times(1)).processMenuDeleted(id);
}
@Test
public void testDeleteMenu_menuNotExist() {
void testDeleteMenu_menuNotExist() {
assertServiceException(() -> menuService.deleteMenu(randomLongId()),
MENU_NOT_EXISTS);
}
@Test
public void testDeleteMenu_existChildren() {
// mock 数据(构造父子菜单)
MenuDO sonMenu = createParentAndSonMenu();
// 准备参数
Long parentId = sonMenu.getParentId();
void testDeleteMenu_existChildren() {
Long menuId = 100L;
when(menuMapper.selectCountByParentId(menuId)).thenReturn(1L);
// 调用并断言异常
assertServiceException(() -> menuService.deleteMenu(parentId), MENU_EXISTS_CHILDREN);
assertServiceException(() -> menuService.deleteMenu(menuId), MENU_EXISTS_CHILDREN);
}
@Test
public void testGetMenuList_all() {
void testGetMenuList_all() {
// mock 数据
MenuDO menu100 = randomPojo(MenuDO.class);
menuMapper.insert(menu100);
MenuDO menu101 = randomPojo(MenuDO.class);
menuMapper.insert(menu101);
// 准备参数
when(menuMapper.selectList()).thenReturn(List.of(menu100, menu101));
// 调用
List<MenuDO> list = menuService.getMenuList();
@@ -144,16 +307,13 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testGetMenuList() {
void testGetMenuList() {
// mock 数据
MenuDO menuDO = randomPojo(MenuDO.class, o -> o.setName("晨丰").setStatus(CommonStatusEnum.ENABLE.getStatus()));
menuMapper.insert(menuDO);
// 测试 status 不匹配
menuMapper.insert(cloneIgnoreId(menuDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 name 不匹配
menuMapper.insert(cloneIgnoreId(menuDO, o -> o.setName("")));
// 准备参数
MenuListReqVO reqVO = new MenuListReqVO().setName("").setStatus(CommonStatusEnum.ENABLE.getStatus());
when(menuMapper.selectList(reqVO)).thenReturn(List.of(menuDO));
// 调用
List<MenuDO> result = menuService.getMenuList(reqVO);
@@ -163,22 +323,21 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testGetMenuListByTenant() {
void testGetMenuListByTenant() {
// mock 数据
MenuDO menu100 = randomPojo(MenuDO.class, o -> o.setId(100L).setStatus(CommonStatusEnum.ENABLE.getStatus()));
menuMapper.insert(menu100);
MenuDO menu101 = randomPojo(MenuDO.class, o -> o.setId(101L).setStatus(CommonStatusEnum.DISABLE.getStatus()));
menuMapper.insert(menu101);
MenuDO menu102 = randomPojo(MenuDO.class, o -> o.setId(102L).setStatus(CommonStatusEnum.ENABLE.getStatus()));
menuMapper.insert(menu102);
// mock 过滤菜单
Set<Long> menuIds = asSet(100L, 101L);
doNothing().when(tenantService).handleOrganMenu(argThat(handler -> {
Set<Long> menuIds = asSet(100L);
doNothing().when(organService).handleOrganMenu(argThat(handler -> {
handler.handle(menuIds);
return true;
}));
// 准备参数
MenuListReqVO reqVO = new MenuListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus());
when(menuMapper.selectList(reqVO)).thenReturn(new ArrayList<>(Arrays.asList(menu100, menu101, menu102)));
// 调用
List<MenuDO> result = menuService.getMenuListByOrgan(reqVO);
@@ -188,15 +347,32 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testGetMenuIdListByPermissionFromCache() {
void testGetMenuList1_empty() {
List<MenuDO> menuList1 = menuService.getMenuList1(Collections.emptyList());
assertEquals(0, menuList1.size());
}
@Test
void testGetMenuList1_success() {
MenuDO menuDO = randomPojo(MenuDO.class);
Set<Long> ids = Collections.singleton(menuDO.getId());
when(menuMapper.selectByIds(ids)).thenReturn(List.of(menuDO));
List<MenuDO> menuList1 = menuService.getMenuList1(ids);
assertEquals(menuDO, menuList1.get(0));
}
@Test
void testGetMenuIdListByPermissionFromCache() {
// mock 数据
MenuDO menu100 = randomPojo(MenuDO.class);
menuMapper.insert(menu100);
MenuDO menu101 = randomPojo(MenuDO.class);
menuMapper.insert(menu101);
// 准备参数
String permission = menu100.getPermission();
when(menuMapper.selectListByPermission(menu100.getPermission())).thenReturn(List.of(menu100));
// 调用
List<Long> ids = menuService.getMenuIdListByPermissionFromCache(permission);
// 断言
@@ -205,14 +381,13 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testGetMenuList_ids() {
void testGetMenuList_ids() {
// mock 数据
MenuDO menu100 = randomPojo(MenuDO.class);
menuMapper.insert(menu100);
MenuDO menu101 = randomPojo(MenuDO.class);
menuMapper.insert(menu101);
// 准备参数
Collection<Long> ids = Collections.singleton(menu100.getId());
when(menuMapper.selectByIds(ids)).thenReturn(List.of(menu100));
// 调用
List<MenuDO> list = menuService.getMenuList(ids);
@@ -222,12 +397,13 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testGetMenu() {
void testGetMenu() {
// mock 数据
MenuDO menu = randomPojo(MenuDO.class);
menuMapper.insert(menu);
// 准备参数
Long id = menu.getId();
when(menuMapper.selectById(id)).thenReturn(menu);
// 调用
MenuDO dbMenu = menuService.getMenu(id);
@@ -236,38 +412,41 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testValidateParentMenu_success() {
void testValidateParentMenu_success() {
// mock 数据
MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", 0L);
menuMapper.insert(menuDO);
// 准备参数
Long parentId = menuDO.getId();
when(menuMapper.selectById(parentId)).thenReturn(menuDO);
// 调用,无需断言
menuService.validateParentMenu(parentId, null);
menuService.validateParentMenu(null, null);
}
@Test
public void testValidateParentMenu_canNotSetSelfToBeParent() {
void testValidateParentMenu_canNotSetSelfToBeParent() {
// 调用,并断言异常
assertServiceException(() -> menuService.validateParentMenu(1L, 1L),
MENU_PARENT_ERROR);
}
@Test
public void testValidateParentMenu_parentNotExist() {
void testValidateParentMenu_parentNotExist() {
// 调用,并断言异常
assertServiceException(() -> menuService.validateParentMenu(randomLongId(), null),
MENU_PARENT_NOT_EXISTS);
}
@Test
public void testValidateParentMenu_parentTypeError() {
void testValidateParentMenu_parentTypeError() {
// mock 数据
MenuDO menuDO = buildMenuDO(MenuTypeEnum.BUTTON, "parent", 0L);
menuMapper.insert(menuDO);
// 准备参数
Long parentId = menuDO.getId();
when(menuMapper.selectById(parentId)).thenReturn(menuDO);
// 调用,并断言异常
assertServiceException(() -> menuService.validateParentMenu(parentId, null),
@@ -275,9 +454,9 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testValidateMenu_success() {
void testValidateMenu_success() {
// mock 父子菜单
MenuDO sonMenu = createParentAndSonMenu();
MenuDO sonMenu = randomPojo(MenuDO.class);
// 准备参数
Long parentId = sonMenu.getParentId();
Long otherSonMenuId = randomLongId();
@@ -288,44 +467,221 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
}
@Test
public void testValidateMenu_sonMenuNameDuplicate() {
void testValidateMenu_sonMenuNameDuplicate() {
// mock 父子菜单
MenuDO sonMenu = createParentAndSonMenu();
MenuDO sonMenu = randomPojo(MenuDO.class);
// 准备参数
Long parentId = sonMenu.getParentId();
Long otherSonMenuId = randomLongId();
String otherSonMenuName = sonMenu.getName(); //相同名称
when(menuMapper.selectByParentIdAndNameAndSourceType(parentId, otherSonMenuName, MenuSourceTypeEnum.PRODUCTION.getType())).thenReturn(sonMenu);
// 调用,并断言异常
assertServiceException(() -> menuService.validateMenu(parentId, otherSonMenuName, otherSonMenuId, MenuSourceTypeEnum.PRODUCTION.getType()),
MENU_NAME_DUPLICATE);
}
// ====================== 初始化方法 ======================
@Test
void testValidateMenu_sonMenuNameDuplicate_whenNull() {
// mock 父子菜单
MenuDO sonMenu = randomPojo(MenuDO.class);
// 准备参数
Long parentId = sonMenu.getParentId();
String otherSonMenuName = sonMenu.getName(); //相同名称
/**
* 插入父子菜单,返回子菜单
*
* @return 子菜单
*/
private MenuDO createParentAndSonMenu() {
// 构造父子菜单
MenuDO parentMenuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", MenuDO.ID_ROOT);
menuMapper.insert(parentMenuDO);
// 构建子菜单
MenuDO sonMenuDO = buildMenuDO(MenuTypeEnum.MENU, "testSonName",
parentMenuDO.getParentId());
menuMapper.insert(sonMenuDO);
return sonMenuDO;
when(menuMapper.selectByParentIdAndNameAndSourceType(parentId, otherSonMenuName, MenuSourceTypeEnum.PRODUCTION.getType())).thenReturn(sonMenu);
// 调用,并断言异常
assertServiceException(() -> menuService.validateMenu(parentId, otherSonMenuName, null, MenuSourceTypeEnum.PRODUCTION.getType()),
MENU_NAME_DUPLICATE);
}
@Test
void testGetManageEndPointMenuList() {
List<MenuDO> mockList = List.of(new MenuDO());
when(menuMapper.selectListIn(
anyCollection(),
eq(true),
anyString()
)).thenReturn(mockList);
List<MenuDO> result = menuService.getManageEndPointMenuList(List.of(1L, 2L));
assertSame(mockList, result);
verify(menuMapper).selectListIn(
anyCollection(),
eq(true),
anyString()
);
}
@Test
void testGetCustomEndPointMenuList() {
List<MenuDO> mockList = List.of(new MenuDO());
when(menuMapper.selectListIn(
anyCollection(),
eq(false),
anyString()
)).thenReturn(mockList);
List<MenuDO> result = menuService.getCustomEndPointMenuList(List.of(1L, 2L));
assertSame(mockList, result);
verify(menuMapper).selectListIn(
anyCollection(),
eq(false),
anyString()
);
}
// ====================== 初始化方法 ======================
private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId) {
return buildMenuDO(type, name, parentId, randomCommonStatus());
}
private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId, Integer status) {
return randomPojo(MenuDO.class, o -> o.setId(null).setName(name).setParentId(parentId)
return randomPojo(MenuDO.class, o -> o.setName(name).setParentId(parentId)
.setType(type.getType()).setStatus(status));
}
@Test
void testTrans_errorCode() {
// mock properties
when(transProperties.getAppId()).thenReturn("appId");
when(transProperties.getSecurityKey()).thenReturn("key");
when(transProperties.getApiHost()).thenReturn("host");
MenuTransReqVO req = new MenuTransReqVO();
req.setTargetLanguage("en");
when(menuMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(List.of(randomPojo(MenuDO.class)));
String errorJson = """
{
"error_code": "54001"
}
""";
try (MockedConstruction<TransApi> mocked =
Mockito.mockConstruction(TransApi.class,
(mock, context) -> when(mock.getTransResult(any(), any(), any()))
.thenReturn(errorJson))) {
assertThrows(ServiceException.class,
() -> menuService.trans(req));
}
verify(menuI18nMapper, never()).insertBatch(any());
}
@Test
void testTrans_success_en() {
// mock properties
when(transProperties.getAppId()).thenReturn("appId");
when(transProperties.getSecurityKey()).thenReturn("key");
when(transProperties.getApiHost()).thenReturn("host");
MenuTransReqVO req = new MenuTransReqVO();
req.setTargetLanguage("en");
when(menuMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(List.of(randomPojo(MenuDO.class, o -> {
o.setName("系统管理");
})));
String okJson = """
{
"trans_result": [
{ "src": "系统管理", "dst": "system management" }
]
}
""";
try (MockedConstruction<TransApi> mocked =
Mockito.mockConstruction(TransApi.class,
(mock, context) -> when(mock.getTransResult(any(), any(), any()))
.thenReturn(okJson))) {
menuService.trans(req);
}
ArgumentCaptor<List<MenuI18nDO>> captor =
ArgumentCaptor.forClass(List.class);
verify(menuI18nMapper).insertBatch(captor.capture());
MenuI18nDO i18n = captor.getValue().get(0);
assertEquals("System Management", i18n.getMenuName());
assertEquals("en", i18n.getLocale());
}
@Test
void testTrans_srcNotMatch() {
MenuTransReqVO req = new MenuTransReqVO();
req.setTargetLanguage("en");
when(menuMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(List.of(randomPojo(MenuDO.class, o -> {
o.setName("系统管理");
})));
String json = """
{
"trans_result": [
{ "src": "用户管理", "dst": "user management" }
]
}
""";
try (MockedConstruction<TransApi> mocked =
Mockito.mockConstruction(TransApi.class,
(mock, context) -> when(mock.getTransResult(any(), any(), any()))
.thenReturn(json))) {
menuService.trans(req);
}
verify(menuI18nMapper, never()).insertBatch(any());
}
@Test
void testTrans_partialSuccess() {
MenuTransReqVO req = new MenuTransReqVO();
req.setTargetLanguage(LanguageEnum.ZH.getLanguage());
when(menuMapper.selectList(any(LambdaQueryWrapper.class))).thenReturn(
List.of(
randomPojo(MenuDO.class, o -> o.setName("系统管理")),
randomPojo(MenuDO.class, o -> o.setName("用户管理"))
)
);
String json = """
{
"trans_result": [
{ "src": "系统管理", "dst": "system management" },
{ "src": "角色管理", "dst": "role management" }
]
}
""";
try (MockedConstruction<TransApi> mocked =
Mockito.mockConstruction(TransApi.class,
(mock, context) -> when(mock.getTransResult(any(), any(), any()))
.thenReturn(json))) {
menuService.trans(req);
}
ArgumentCaptor<List<MenuI18nDO>> captor =
ArgumentCaptor.forClass(List.class);
verify(menuI18nMapper).insertBatch(captor.capture());
assertEquals(1, captor.getValue().size());
}
}