15 changed files with 464 additions and 52 deletions
-
13build.gradle
-
BINmatrix-spray.db
-
45src/main/java/com/qyft/ms/app/common/generator/PathGenerator.java
-
56src/main/java/com/qyft/ms/app/common/generator/RectangleGrid.java
-
26src/main/java/com/qyft/ms/app/controller/CMDController.java
-
8src/main/java/com/qyft/ms/app/controller/MatrixCraftController.java
-
11src/main/java/com/qyft/ms/app/model/vo/MatrixCraftResult.java
-
57src/main/java/com/qyft/ms/app/service/CMDService.java
-
5src/main/java/com/qyft/ms/app/service/MatrixCraftService.java
-
3src/main/java/com/qyft/ms/app/service/WebSocketService.java
-
2src/main/java/com/qyft/ms/app/service/impl/ISysSettingsServiceImpl.java
-
31src/main/java/com/qyft/ms/app/service/impl/MatrixCraftServiceImpl.java
-
2src/main/resources/application.yml
-
144src/test/java/com/qyft/ms/CMDServiceTest.java
-
111src/test/java/com/qyft/ms/SprayTest.java
@ -0,0 +1,56 @@ |
|||||
|
package com.qyft.ms.app.common.generator; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
public class RectangleGrid { |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
// 示例输入 |
||||
|
int x1 = 0, y1 = 0; // 左上角坐标 |
||||
|
int x2 = 10, y2 = 10; // 右下角坐标 |
||||
|
int spacing = 2; // 间距值 |
||||
|
String moveType = "horizontal"; // 移动类型:horizontal(横向)或 vertical(纵向) |
||||
|
|
||||
|
// 生成坐标点 |
||||
|
List<int[]> points = generatePoints(x1, y1, x2, y2, spacing, moveType); |
||||
|
|
||||
|
// 输出结果 |
||||
|
for (int[] point : points) { |
||||
|
System.out.println("(" + point[0] + ", " + point[1] + ")"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成铺满矩形区域的坐标点 |
||||
|
* |
||||
|
* @param x1 左上角 x 坐标 |
||||
|
* @param y1 左上角 y 坐标 |
||||
|
* @param x2 右下角 x 坐标 |
||||
|
* @param y2 右下角 y 坐标 |
||||
|
* @param spacing 间距值 |
||||
|
* @param moveType 移动类型:horizontal(横向)或 vertical(纵向) |
||||
|
* @return 坐标点列表 |
||||
|
*/ |
||||
|
public static List<int[]> generatePoints(int x1, int y1, int x2, int y2, int spacing, String moveType) { |
||||
|
List<int[]> points = new ArrayList<>(); |
||||
|
|
||||
|
if (moveType.equalsIgnoreCase("horizontal")) { |
||||
|
// 横向移动:每一行的起点和终点 |
||||
|
for (int y = y1; y <= y2; y += spacing) { |
||||
|
points.add(new int[]{x1, y}); // 起点 |
||||
|
points.add(new int[]{x2, y}); // 终点 |
||||
|
} |
||||
|
} else if (moveType.equalsIgnoreCase("vertical")) { |
||||
|
// 纵向移动:每一列的起点和终点 |
||||
|
for (int x = x1; x <= x2; x += spacing) { |
||||
|
points.add(new int[]{x, y1}); // 起点 |
||||
|
points.add(new int[]{x, y2}); // 终点 |
||||
|
} |
||||
|
} else { |
||||
|
throw new IllegalArgumentException("Invalid move type. Use 'horizontal' or 'vertical'."); |
||||
|
} |
||||
|
|
||||
|
return points; |
||||
|
} |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package com.qyft.ms.app.model.vo; |
||||
|
|
||||
|
import com.qyft.ms.app.model.entity.MatrixCraft; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class MatrixCraftResult extends MatrixCraft { |
||||
|
|
||||
|
private String matrixName; |
||||
|
|
||||
|
} |
@ -0,0 +1,144 @@ |
|||||
|
package com.qyft.ms; |
||||
|
|
||||
|
import com.qyft.ms.app.model.form.CMDForm; |
||||
|
import com.qyft.ms.app.model.vo.ExecutionResult; |
||||
|
import com.qyft.ms.app.service.CMDService; |
||||
|
import com.qyft.ms.app.service.OperationLogService; |
||||
|
import com.qyft.ms.app.service.WebSocketService; |
||||
|
import com.qyft.ms.device.service.DeviceTcpCMDService; |
||||
|
import org.junit.jupiter.api.BeforeEach; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.mockito.InjectMocks; |
||||
|
import org.mockito.Mock; |
||||
|
import org.mockito.MockitoAnnotations; |
||||
|
import org.springframework.boot.test.context.SpringBootTest; |
||||
|
import org.springframework.test.context.ActiveProfiles; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.function.Supplier; |
||||
|
|
||||
|
import static org.junit.jupiter.api.Assertions.*; |
||||
|
import static org.mockito.ArgumentMatchers.*; |
||||
|
import static org.mockito.Mockito.*; |
||||
|
|
||||
|
@ActiveProfiles("test") |
||||
|
@SpringBootTest |
||||
|
public class CMDServiceTest { |
||||
|
|
||||
|
@Mock |
||||
|
private DeviceTcpCMDService deviceTcpCMDService; |
||||
|
|
||||
|
@Mock |
||||
|
private WebSocketService webSocketService; |
||||
|
|
||||
|
@Mock |
||||
|
private OperationLogService operationLogService; |
||||
|
|
||||
|
@InjectMocks |
||||
|
private CMDService cmdService; |
||||
|
|
||||
|
private CMDForm form; |
||||
|
|
||||
|
@BeforeEach |
||||
|
void setUp() { |
||||
|
MockitoAnnotations.openMocks(this); |
||||
|
form = new CMDForm(); |
||||
|
form.setCommandId("test-command"); |
||||
|
form.setCommandName("test-command"); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void testMoveMotorToPosition_Success() { |
||||
|
// 准备参数 |
||||
|
Map<String, Object> params = new HashMap<>(); |
||||
|
params.put("axis", "x"); |
||||
|
params.put("position", 100.0); |
||||
|
form.setParams(params); |
||||
|
|
||||
|
// 模拟设备服务调用 |
||||
|
when(deviceTcpCMDService.moveMotorToPosition(anyString(), anyDouble())).thenReturn(true); |
||||
|
|
||||
|
// 执行测试 |
||||
|
boolean result = cmdService.moveMotorToPosition(form); |
||||
|
|
||||
|
// 验证结果 |
||||
|
assertTrue(result); |
||||
|
verify(deviceTcpCMDService, times(1)).moveMotorToPosition("x", 100.0); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void testStartWork_InvalidPosition() { |
||||
|
// 准备无效参数 |
||||
|
Map<String, Object> params = new HashMap<>(); |
||||
|
params.put("position", new ArrayList<>()); // 空位置列表 |
||||
|
form.setParams(params); |
||||
|
|
||||
|
// 执行测试 |
||||
|
String result = cmdService.startWork(form); |
||||
|
|
||||
|
// 验证返回错误信息 |
||||
|
assertEquals("position参数错误", result); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void testStartWork_PathGeneration() { |
||||
|
// 准备有效参数 |
||||
|
Map<String, Object> params = new HashMap<>(); |
||||
|
List<Map<String, Integer>> positions = new ArrayList<>(); |
||||
|
Map<String, Integer> pos = new HashMap<>(); |
||||
|
pos.put("x1", 10); |
||||
|
pos.put("y1", 20); |
||||
|
pos.put("x2", 30); |
||||
|
pos.put("y2", 40); |
||||
|
pos.put("index", 0); |
||||
|
positions.add(pos); |
||||
|
params.put("position", positions); |
||||
|
params.put("space", 5); |
||||
|
params.put("routeType", 1); |
||||
|
params.put("height", 50); |
||||
|
params.put("movementSpeed", 100); |
||||
|
form.setParams(params); |
||||
|
|
||||
|
// 模拟依赖项 |
||||
|
when(deviceTcpCMDService.switchThreeWayValveToSpray()).thenReturn(true); |
||||
|
when(deviceTcpCMDService.setMotorSpeed(anyString(), anyInt())).thenReturn(true); |
||||
|
when(deviceTcpCMDService.moveMotorToPosition(anyString(), anyDouble())).thenReturn(true); |
||||
|
|
||||
|
// 执行测试 |
||||
|
String result = cmdService.startWork(form); |
||||
|
|
||||
|
// 验证命令链长度 |
||||
|
assertNotNull(result); |
||||
|
verify(deviceTcpCMDService, atLeastOnce()).switchThreeWayValveToSpray(); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void testControlValve_NozzleOpen() { |
||||
|
Map<String, Object> params = new HashMap<>(); |
||||
|
params.put("valveType", "Nozzle"); |
||||
|
params.put("isOpen", true); |
||||
|
form.setParams(params); |
||||
|
|
||||
|
when(deviceTcpCMDService.controlValve(anyString(), anyBoolean())).thenReturn(true); |
||||
|
|
||||
|
boolean result = cmdService.controlValve(form); |
||||
|
assertTrue(result); |
||||
|
verify(deviceTcpCMDService).controlValve("Nozzle", true); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void testRun_CommandFailure() { |
||||
|
// 模拟一个失败的指令 |
||||
|
List<Supplier<Boolean>> cmdList = new ArrayList<>(); |
||||
|
cmdList.add(() -> false); // 直接返回失败 |
||||
|
|
||||
|
// 执行内部方法 |
||||
|
cmdService.run(cmdList, form); |
||||
|
|
||||
|
// 验证WebSocket错误消息推送 |
||||
|
verify(webSocketService).pushMsg(any(), any(ExecutionResult.class)); |
||||
|
} |
||||
|
} |
@ -0,0 +1,111 @@ |
|||||
|
package com.qyft.ms; |
||||
|
|
||||
|
import com.qyft.ms.app.model.entity.OperationLog; |
||||
|
import com.qyft.ms.app.model.entity.SysSettings; |
||||
|
import com.qyft.ms.app.model.form.CMDForm; |
||||
|
import com.qyft.ms.app.service.*; |
||||
|
import com.qyft.ms.device.service.DeviceTcpCMDService; |
||||
|
import org.junit.jupiter.api.BeforeEach; |
||||
|
import org.junit.jupiter.api.Test; |
||||
|
import org.mockito.*; |
||||
|
|
||||
|
import java.util.*; |
||||
|
|
||||
|
import static com.qyft.ms.app.common.generator.PathGenerator.generatePathPoints; |
||||
|
import static org.mockito.Mockito.*; |
||||
|
|
||||
|
public class SprayTest { |
||||
|
|
||||
|
@InjectMocks |
||||
|
private CMDService cmdService; |
||||
|
|
||||
|
@Mock |
||||
|
private WebSocketService webSocketService; |
||||
|
@Mock |
||||
|
private DeviceTcpCMDService deviceTcpCMDService; |
||||
|
@Mock |
||||
|
private OperationLogService operationLogService; |
||||
|
@Mock |
||||
|
private MatrixCraftService matrixCraftService; |
||||
|
@Mock |
||||
|
private ISysSettingsService sysSettingsService; |
||||
|
|
||||
|
@BeforeEach |
||||
|
void setUp() { |
||||
|
MockitoAnnotations.openMocks(this); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void testStartWork() { |
||||
|
// 1. 准备模拟数据 |
||||
|
CMDForm form = new CMDForm(); |
||||
|
form.setCommandId("cmd123"); |
||||
|
form.setCommandName("startWork"); |
||||
|
|
||||
|
Map<String, Object> params = new HashMap<>(); |
||||
|
params.put("space", 1); |
||||
|
params.put("routeType", 1); |
||||
|
params.put("movementSpeed", 100); |
||||
|
params.put("height", 50); |
||||
|
params.put("voltage", 100); |
||||
|
params.put("matrixFlowVelocity", 20); |
||||
|
params.put("matrixCraftId", 1); |
||||
|
|
||||
|
List<Map<String, Integer>> positionList = new ArrayList<>(); |
||||
|
Map<String, Integer> position = new HashMap<>(); |
||||
|
position.put("x1", 10); |
||||
|
position.put("y1", 20); |
||||
|
position.put("x2", 30); |
||||
|
position.put("y2", 40); |
||||
|
position.put("index", 0); |
||||
|
positionList.add(position); |
||||
|
params.put("position", positionList); |
||||
|
|
||||
|
form.setParams(params); |
||||
|
|
||||
|
// 2. 模拟依赖行为 |
||||
|
SysSettings mockSetting = new SysSettings(); |
||||
|
mockSetting.setValue("100,200,300"); // 模拟托盘坐标 |
||||
|
when(sysSettingsService.getSlidePositionList()).thenReturn(Collections.singletonList(mockSetting)); |
||||
|
|
||||
|
when(deviceTcpCMDService.switchThreeWayValveToSpray()).thenReturn(true); |
||||
|
when(deviceTcpCMDService.setMotorSpeed(anyString(), anyInt())).thenReturn(true); |
||||
|
when(deviceTcpCMDService.moveMotorToPosition(anyString(), anyDouble())).thenReturn(true); |
||||
|
when(deviceTcpCMDService.turnOnHighVoltage(anyDouble())).thenReturn(true); |
||||
|
when(deviceTcpCMDService.controlValve(anyString(), anyBoolean())).thenReturn(true); |
||||
|
when(deviceTcpCMDService.syringePumpMoveAtSpeed(anyInt())).thenReturn(true); |
||||
|
when(deviceTcpCMDService.turnOffSyringePump()).thenReturn(true); |
||||
|
when(deviceTcpCMDService.motorMoveToHome(anyString())).thenReturn(true); |
||||
|
|
||||
|
// OperationLog mockLog = new OperationLog(); |
||||
|
// when(operationLogService.getIng()).thenReturn(mockLog); |
||||
|
// when(operationLogService.add(any())).thenReturn(true); |
||||
|
// when(operationLogService.updateById(any())).thenReturn(true); |
||||
|
|
||||
|
// 3. 调用测试方法 |
||||
|
String result = cmdService.startWork(form); |
||||
|
|
||||
|
// 4. 验证 |
||||
|
verify(deviceTcpCMDService, times(1)).switchThreeWayValveToSpray(); |
||||
|
verify(deviceTcpCMDService, times(1)).setMotorSpeed("x", 100); |
||||
|
verify(deviceTcpCMDService, times(1)).setMotorSpeed("y", 100); |
||||
|
verify(deviceTcpCMDService, times(1)).setMotorSpeed("z", 100); |
||||
|
verify(deviceTcpCMDService, times(1)).moveMotorToPosition("z", 350); // z + height (300+50) |
||||
|
verify(deviceTcpCMDService, times(1)).moveMotorToPosition("x", 110); // x+10 |
||||
|
verify(deviceTcpCMDService, times(1)).moveMotorToPosition("y", 220); // y+20 |
||||
|
verify(deviceTcpCMDService, times(1)).turnOnHighVoltage(100); |
||||
|
|
||||
|
// 日志校验 |
||||
|
// verify(operationLogService, times(1)).add(any(OperationLog.class)); |
||||
|
// verify(operationLogService, times(1)).updateById(any(OperationLog.class)); |
||||
|
|
||||
|
// 轨迹移动和其他控制指令同理,这里可以补充更多verify |
||||
|
|
||||
|
verify(deviceTcpCMDService, atLeastOnce()).moveMotorToPosition(eq("x"), anyDouble()); |
||||
|
verify(deviceTcpCMDService, atLeastOnce()).moveMotorToPosition(eq("y"), anyDouble()); |
||||
|
|
||||
|
|
||||
|
// 6. 说明 |
||||
|
System.out.println("✅ startWork测试通过!"); |
||||
|
} |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue