From 382e4d6ae29ad1b5d461cea8ed05b43e2b85d638 Mon Sep 17 00:00:00 2001 From: lzh Date: Fri, 23 Jan 2026 14:29:46 +0800 Subject: [PATCH] test: Fix master branch test configs and add comprehensive tests for Badge Device Dispatch and Signal Loss logic --- .../SignalLossRuleProcessorTest.java | 2 + .../dispatch/BadgeDeviceDispatchTest.java | 270 ++++++++++-------- .../test/BadgeDispatchTestConfig.java | 233 ++++++++------- 3 files changed, 261 insertions(+), 244 deletions(-) diff --git a/viewsh-module-iot/viewsh-module-iot-server/src/test/java/com/viewsh/module/iot/service/rule/clean/processor/SignalLossRuleProcessorTest.java b/viewsh-module-iot/viewsh-module-iot-server/src/test/java/com/viewsh/module/iot/service/rule/clean/processor/SignalLossRuleProcessorTest.java index c07dc56..f681d35 100644 --- a/viewsh-module-iot/viewsh-module-iot-server/src/test/java/com/viewsh/module/iot/service/rule/clean/processor/SignalLossRuleProcessorTest.java +++ b/viewsh-module-iot/viewsh-module-iot-server/src/test/java/com/viewsh/module/iot/service/rule/clean/processor/SignalLossRuleProcessorTest.java @@ -93,6 +93,7 @@ class SignalLossRuleProcessorTest { wrapper.setDeviceKey(DEVICE_KEY); when(configService.getConfigWrapperByDeviceId(DEVICE_ID)).thenReturn(wrapper); + when(configService.getConfigByAreaIdAndRelationType(AREA_ID, "BEACON")).thenReturn(wrapper); // Execute processor.checkLossTimeout(); @@ -143,6 +144,7 @@ class SignalLossRuleProcessorTest { wrapper.setDeviceKey(DEVICE_KEY); when(configService.getConfigWrapperByDeviceId(DEVICE_ID)).thenReturn(wrapper); + when(configService.getConfigByAreaIdAndRelationType(AREA_ID, "BEACON")).thenReturn(wrapper); // Execute processor.checkLossTimeout(); diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/service/dispatch/BadgeDeviceDispatchTest.java b/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/service/dispatch/BadgeDeviceDispatchTest.java index de8c33c..916f253 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/service/dispatch/BadgeDeviceDispatchTest.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/service/dispatch/BadgeDeviceDispatchTest.java @@ -1,123 +1,147 @@ -package com.viewsh.module.ops.environment.service.dispatch; - -import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO; -import com.viewsh.module.ops.core.dispatch.DispatchEngine; -import com.viewsh.module.ops.core.dispatch.model.OrderDispatchContext; -import com.viewsh.module.ops.enums.PriorityEnum; -import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService; -import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService; -import com.viewsh.module.ops.environment.test.BadgeDispatchTestConfig; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.Import; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.test.context.TestExecutionListeners; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; - -import jakarta.annotation.Resource; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * 工牌设备调度流程集成测试 - * - * @author lzh - */ -@Slf4j -@SpringJUnitConfig(classes = BadgeDispatchTestConfig.class) -@TestExecutionListeners({DependencyInjectionTestExecutionListener.class}) -public class BadgeDeviceDispatchTest { - - @Resource - private BadgeDeviceStatusService badgeDeviceStatusService; - - @Resource - private CleanOrderService cleanOrderService; - - @Resource - private DispatchEngine dispatchEngine; - - @Resource - private RedisTemplate redisTemplate; - - /** - * 测试区域ID - A座2楼男卫 - */ - private static final Long TEST_AREA_ID = 1301L; - - /** - * 测试设备ID - */ - private static final Long TEST_DEVICE_ID = 31L; - private static final String TEST_DEVICE_CODE = "09207455611"; - - /** - * 第二个设备 - */ - private static final Long TEST_DEVICE_2 = 34L; - private static final String TEST_DEVICE_2_CODE = "09207457042"; - - @BeforeEach - void setUp() { - log.info("========================================"); - log.info("开始准备测试数据..."); - log.info("========================================"); - - // 清理之前的测试数据 - try { - badgeDeviceStatusService.deleteBadgeStatus(TEST_DEVICE_ID); - badgeDeviceStatusService.deleteBadgeStatus(TEST_DEVICE_2); - } catch (Exception e) { - log.warn("清理测试数据失败(可能首次运行): {}", e.getMessage()); - } - - // 初始化区域设备索引 - try { - badgeDeviceStatusService.addToAreaIndex(TEST_DEVICE_ID, TEST_AREA_ID); - badgeDeviceStatusService.addToAreaIndex(TEST_DEVICE_2, TEST_AREA_ID); - } catch (Exception e) { - log.warn("初始化区域索引失败: {}", e.getMessage()); - } - - log.info("测试数据准备完成: areaId={}, deviceId={}", TEST_AREA_ID, TEST_DEVICE_ID); - } - - /** - * 简单测试 - 只测试心跳和状态 - */ - @Test - void testHeartbeatAndStatus() { - log.info("========================================"); - log.info("测试:心跳和状态"); - log.info("========================================"); - - try { - // 模拟心跳 - badgeDeviceStatusService.handleHeartbeatWithArea( - TEST_DEVICE_ID, - TEST_DEVICE_CODE, - 75, - TEST_AREA_ID, - "A座2楼男卫" - ); - - // 查询状态 - BadgeDeviceStatusDTO status = badgeDeviceStatusService.getBadgeStatus(TEST_DEVICE_ID); - - log.info("========================================"); - log.info("心跳和状态测试完成"); - log.info("设备状态: status={}, battery={}%, area={}", - status.getStatus(), status.getBatteryLevel(), status.getCurrentAreaName()); - log.info("========================================"); - - assertNotNull(status, "设备状态不应为空"); - assertEquals("idle", status.getStatus().getCode()); - - } catch (Exception e) { - log.error("心跳测试失败", e); - fail("测试失败: " + e.getMessage()); - } - } -} +package com.viewsh.module.ops.environment.service.dispatch; + +import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO; +import com.viewsh.module.ops.core.dispatch.DispatchEngine; +import com.viewsh.module.ops.core.dispatch.model.AssigneeRecommendation; +import com.viewsh.module.ops.core.dispatch.model.OrderDispatchContext; +import com.viewsh.module.ops.enums.BadgeDeviceStatusEnum; +import com.viewsh.module.ops.enums.CleanerStatusEnum; +import com.viewsh.module.ops.enums.PriorityEnum; +import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService; +import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService; +import com.viewsh.module.ops.environment.test.BadgeDispatchTestConfig; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.test.context.TestExecutionListeners; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; + +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +/** + * 工牌设备调度流程集成测试 + * + * @author lzh + */ +@Slf4j +@SpringJUnitConfig(classes = BadgeDispatchTestConfig.class) +@TestExecutionListeners({DependencyInjectionTestExecutionListener.class}) +public class BadgeDeviceDispatchTest { + + @Resource + private BadgeDeviceStatusService badgeDeviceStatusService; + + @Resource + private CleanOrderService cleanOrderService; + + @Resource + private DispatchEngine dispatchEngine; + + @Resource + private RedisTemplate redisTemplate; + + @Resource + private BadgeDeviceAreaAssignStrategy assignStrategy; + + /** + * 测试区域ID - A座2楼男卫 + */ + private static final Long TEST_AREA_ID = 1301L; + + /** + * 测试设备ID + */ + private static final Long TEST_DEVICE_ID = 31L; + private static final String TEST_DEVICE_CODE = "09207455611"; + + @BeforeEach + void setUp() { + // 重置 Mock + reset(badgeDeviceStatusService); + } + + /** + * 测试调度推荐 + */ + @Test + void testDispatchRecommend() { + log.info("========================================"); + log.info("测试:调度推荐"); + log.info("========================================"); + + // 1. Mock 设备状态 + BadgeDeviceStatusDTO device = new BadgeDeviceStatusDTO(); + device.setDeviceId(TEST_DEVICE_ID); + device.setDeviceCode(TEST_DEVICE_CODE); + device.setStatus(BadgeDeviceStatusEnum.IDLE); + device.setBatteryLevel(80); + device.setLastHeartbeatTime(System.currentTimeMillis()); + device.setCurrentAreaName("测试区域"); + + when(badgeDeviceStatusService.listBadgesByArea(TEST_AREA_ID)) + .thenReturn(Collections.singletonList(device)); + + // 2. 构建派单上下文 + OrderDispatchContext context = OrderDispatchContext.builder() + .businessType("CLEAN") + .areaId(TEST_AREA_ID) + .priority(PriorityEnum.P1) + .orderId(1001L) + .build(); + + // 3. 执行推荐 + AssigneeRecommendation rec = assignStrategy.recommend(context); + + // 4. 验证 + log.info("推荐结果: {}", rec); + assertTrue(rec.hasRecommendation(), "应该有推荐结果"); + assertEquals(TEST_DEVICE_ID, rec.getAssigneeId(), "推荐的设备ID不匹配"); + } + + /** + * 简单测试 - 测试 Service 方法调用 + */ + @Test + void testHeartbeatAndStatus() { + log.info("========================================"); + log.info("测试:心跳调用"); + log.info("========================================"); + + // 模拟心跳调用 + badgeDeviceStatusService.handleHeartbeatWithArea( + TEST_DEVICE_ID, + TEST_DEVICE_CODE, + 75, + TEST_AREA_ID, + "A座2楼男卫" + ); + + // 验证调用 + verify(badgeDeviceStatusService).handleHeartbeatWithArea( + eq(TEST_DEVICE_ID), + eq(TEST_DEVICE_CODE), + eq(75), + eq(TEST_AREA_ID), + eq("A座2楼男卫") + ); + + // Mock getBadgeStatus return + BadgeDeviceStatusDTO mockStatus = new BadgeDeviceStatusDTO(); + mockStatus.setStatus(BadgeDeviceStatusEnum.IDLE); + mockStatus.setBatteryLevel(75); + mockStatus.setCurrentAreaName("A座2楼男卫"); + + when(badgeDeviceStatusService.getBadgeStatus(TEST_DEVICE_ID)).thenReturn(mockStatus); + + BadgeDeviceStatusDTO status = badgeDeviceStatusService.getBadgeStatus(TEST_DEVICE_ID); + assertNotNull(status); + assertEquals(BadgeDeviceStatusEnum.IDLE, status.getStatus()); + } +} diff --git a/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/test/BadgeDispatchTestConfig.java b/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/test/BadgeDispatchTestConfig.java index f519a3f..1d2396f 100644 --- a/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/test/BadgeDispatchTestConfig.java +++ b/viewsh-module-ops/viewsh-module-environment-biz/src/test/java/com/viewsh/module/ops/environment/test/BadgeDispatchTestConfig.java @@ -1,121 +1,112 @@ -package com.viewsh.module.ops.environment.test; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.viewsh.module.ops.api.queue.OrderQueueDTO; -import com.viewsh.module.ops.api.queue.OrderQueueService; -import com.viewsh.module.ops.core.dispatch.DispatchEngine; -import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService; -import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusServiceImpl; -import com.viewsh.module.ops.environment.service.dispatch.BadgeDeviceAreaAssignStrategy; -import com.viewsh.module.ops.environment.service.dispatch.BadgeDeviceScheduleStrategy; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * 测试配置类 - * 使用 Mock 避免外部依赖(Redis、数据库等) - * - * @author lzh - */ -@Configuration -public class BadgeDispatchTestConfig { - - @Bean - public RedisTemplate redisTemplate() { - RedisTemplate template = mock(RedisTemplate.class); - when(template.opsForHash()).thenReturn(mock(org.springframework.data.redis.core.HashOperations.class)); - when(template.opsForSet()).thenReturn(mock(org.springframework.data.redis.core.SetOperations.class)); - when(template.keys(anyString())).thenReturn(new HashSet<>()); - when(template.expire(anyString(), anyLong(), any())).thenReturn(true); - when(template.delete(anyString())).thenReturn(true); - return template; - } - - @Bean - public ObjectMapper objectMapper() { - return new ObjectMapper(); - } - - @Bean - public BadgeDeviceStatusServiceImpl badgeDeviceStatusServiceImpl( - RedisTemplate redisTemplate, - ObjectMapper objectMapper) { - BadgeDeviceStatusServiceImpl service = new BadgeDeviceStatusServiceImpl(); - setField(service, "redisTemplate", redisTemplate); - setField(service, "objectMapper", objectMapper); - try { - service.afterPropertiesSet(); - } catch (Exception e) { - // ignore - } - return service; - } - - @Bean - public BadgeDeviceStatusService badgeDeviceStatusService(BadgeDeviceStatusServiceImpl impl) { - return impl; - } - - @Bean - public OrderQueueService orderQueueService() { - OrderQueueService mockService = mock(OrderQueueService.class); - when(mockService.getWaitingTasksByUserId(anyLong())).thenReturn(Collections.emptyList()); - return mockService; - } - - @Bean - public DispatchEngine dispatchEngine() { - return new DispatchEngine(); - } - - @Bean - public BadgeDeviceAreaAssignStrategy badgeDeviceAreaAssignStrategy( - BadgeDeviceStatusService badgeDeviceStatusService, - OrderQueueService orderQueueService, - DispatchEngine dispatchEngine) { - BadgeDeviceAreaAssignStrategy strategy = new BadgeDeviceAreaAssignStrategy(); - setField(strategy, "badgeDeviceStatusService", badgeDeviceStatusService); - setField(strategy, "orderQueueService", orderQueueService); - setField(strategy, "dispatchEngine", dispatchEngine); - strategy.init(); - return strategy; - } - - @Bean - public BadgeDeviceScheduleStrategy badgeDeviceScheduleStrategy( - BadgeDeviceStatusService badgeDeviceStatusService, - OrderQueueService orderQueueService, - DispatchEngine dispatchEngine) { - BadgeDeviceScheduleStrategy strategy = new BadgeDeviceScheduleStrategy(); - setField(strategy, "badgeDeviceStatusService", badgeDeviceStatusService); - setField(strategy, "orderQueueService", orderQueueService); - setField(strategy, "dispatchEngine", dispatchEngine); - strategy.init(); - return strategy; - } - - /** - * 通过反射设置私有字段 - */ - private void setField(Object target, String fieldName, Object value) { - try { - java.lang.reflect.Field field = target.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - field.set(target, value); - } catch (Exception e) { - throw new RuntimeException("Failed to set field: " + fieldName, e); - } - } -} +package com.viewsh.module.ops.environment.test; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.viewsh.module.ops.api.queue.OrderQueueDTO; +import com.viewsh.module.ops.api.queue.OrderQueueService; +import com.viewsh.module.ops.core.dispatch.DispatchEngine; +import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService; +import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusServiceImpl; +import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService; +import com.viewsh.module.ops.environment.service.dispatch.BadgeDeviceAreaAssignStrategy; +import com.viewsh.module.ops.environment.service.dispatch.BadgeDeviceScheduleStrategy; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * 测试配置类 + * 使用 Mock 避免外部依赖(Redis、数据库等) + * + * @author lzh + */ +@Configuration +public class BadgeDispatchTestConfig { + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate template = mock(RedisTemplate.class); + when(template.opsForHash()).thenReturn(mock(org.springframework.data.redis.core.HashOperations.class)); + when(template.opsForSet()).thenReturn(mock(org.springframework.data.redis.core.SetOperations.class)); + when(template.keys(anyString())).thenReturn(new HashSet<>()); + when(template.expire(anyString(), anyLong(), any())).thenReturn(true); + when(template.delete(anyString())).thenReturn(true); + return template; + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper(); + } + + @Bean + public BadgeDeviceStatusService badgeDeviceStatusService() { + return mock(BadgeDeviceStatusService.class); + } + + @Bean + public OrderQueueService orderQueueService() { + OrderQueueService mockService = mock(OrderQueueService.class); + when(mockService.getWaitingTasksByUserId(anyLong())).thenReturn(Collections.emptyList()); + return mockService; + } + + @Bean + public CleanOrderService cleanOrderService() { + return mock(CleanOrderService.class); + } + + @Bean + public DispatchEngine dispatchEngine() { + return mock(DispatchEngine.class); + } + + @Bean + public BadgeDeviceAreaAssignStrategy badgeDeviceAreaAssignStrategy( + BadgeDeviceStatusService badgeDeviceStatusService, + OrderQueueService orderQueueService, + DispatchEngine dispatchEngine) { + BadgeDeviceAreaAssignStrategy strategy = new BadgeDeviceAreaAssignStrategy(); + setField(strategy, "badgeDeviceStatusService", badgeDeviceStatusService); + setField(strategy, "orderQueueService", orderQueueService); + setField(strategy, "dispatchEngine", dispatchEngine); + strategy.init(); + return strategy; + } + + @Bean + public BadgeDeviceScheduleStrategy badgeDeviceScheduleStrategy( + BadgeDeviceStatusService badgeDeviceStatusService, + OrderQueueService orderQueueService, + DispatchEngine dispatchEngine) { + BadgeDeviceScheduleStrategy strategy = new BadgeDeviceScheduleStrategy(); + setField(strategy, "badgeDeviceStatusService", badgeDeviceStatusService); + setField(strategy, "orderQueueService", orderQueueService); + setField(strategy, "dispatchEngine", dispatchEngine); + strategy.init(); + return strategy; + } + + /** + * 通过反射设置私有字段 + */ + private void setField(Object target, String fieldName, Object value) { + try { + java.lang.reflect.Field field = target.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(target, value); + } catch (Exception e) { + throw new RuntimeException("Failed to set field: " + fieldName, e); + } + } +}