Browse Source

feat: 指令单元测试

master
guoapeng 5 months ago
parent
commit
cbab174dda
  1. 13
      build.gradle
  2. BIN
      matrix-spray.db
  3. 47
      src/main/java/com/qyft/ms/app/common/generator/PathGenerator.java
  4. 56
      src/main/java/com/qyft/ms/app/common/generator/RectangleGrid.java
  5. 26
      src/main/java/com/qyft/ms/app/controller/CMDController.java
  6. 8
      src/main/java/com/qyft/ms/app/controller/MatrixCraftController.java
  7. 11
      src/main/java/com/qyft/ms/app/model/vo/MatrixCraftResult.java
  8. 57
      src/main/java/com/qyft/ms/app/service/CMDService.java
  9. 5
      src/main/java/com/qyft/ms/app/service/MatrixCraftService.java
  10. 3
      src/main/java/com/qyft/ms/app/service/WebSocketService.java
  11. 2
      src/main/java/com/qyft/ms/app/service/impl/ISysSettingsServiceImpl.java
  12. 31
      src/main/java/com/qyft/ms/app/service/impl/MatrixCraftServiceImpl.java
  13. 2
      src/main/resources/application.yml
  14. 144
      src/test/java/com/qyft/ms/CMDServiceTest.java
  15. 111
      src/test/java/com/qyft/ms/SprayTest.java

13
build.gradle

@ -40,6 +40,7 @@ dependencies {
implementation group: 'com.alibaba', name: 'fastjson', version: '2.0.54'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-websocket', version: '3.4.2'
implementation group: 'io.netty', name: 'netty-all', version: '4.1.118.Final'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
//++++++++++++++++
//++++++++++++++++
@ -52,6 +53,16 @@ dependencies {
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
// 使JUnit平台运行器
tasks.withType(Test).configureEach {
useJUnitPlatform()
//
reports {
junitXml.required = true // XML格式报告
html.required = true // HTML报告
}
// Windows下常见
systemProperty 'file.encoding', 'UTF-8'
}

BIN
matrix-spray.db

47
src/main/java/com/qyft/ms/app/common/generator/PathGenerator.java

@ -7,6 +7,7 @@ import java.util.List;
/**
* 路径生成器可选择水平之字形(从上往下) 垂直之字形(从左往右)
* 并考虑画笔spacing向内收缩以避免越出外部边界
* 坐标系向右和向下为正
*/
public class PathGenerator {
@ -28,13 +29,13 @@ public class PathGenerator {
}
/**
* [left, right] x [bottom, top] 范围内生成之字形路径
* [left, right] x [top, bottom] 范围内生成之字形路径
* 并考虑画笔 spacing内缩以防越界
*
* @param left 矩形左边界 (数学坐标: 左下角为原点)
* @param left 矩形左边界
* @param right 矩形右边界
* @param bottom 矩形下边界
* @param top 矩形上边界
* @param bottom 矩形下边界
* @param spacing 画笔粗细/间距 (>0)
* @param mode HORIZONTAL_ZIGZAG_TOP_DOWN VERTICAL_ZIGZAG_LEFT_RIGHT
* @return 之字形路径拐点列表 (每个拐点是 (x,y) 的int坐标)
@ -42,15 +43,14 @@ public class PathGenerator {
public static List<Point> generatePathPoints(
int left,
int right,
int bottom,
int top,
int bottom,
int spacing,
MoveMode mode
) {
// 基本校验
if (left >= right || bottom >= top) {
throw new IllegalArgumentException("无效矩形边界: left>=right 或 bottom>=top" + left + ", " + right + " ," + bottom + ", " + top);
if (left >= right || top >= bottom) {
throw new IllegalArgumentException("无效矩形边界: left>=right 或 top>=bottom:" + "top: " +top + ",right: " + right + ",bottom: " + bottom + ",left: "+ left);
}
if (spacing <= 0) {
throw new IllegalArgumentException("spacing必须>0");
@ -60,11 +60,11 @@ public class PathGenerator {
// 留出 spacing 宽度可改成 spacing/2 (半个笔刷)
int effLeft = left + spacing;
int effRight = right - spacing;
int effBottom = bottom + spacing;
int effTop = top - spacing;
int effTop = top + spacing;
int effBottom = bottom - spacing;
// 若收缩后无空间则返回空集合
if (effLeft > effRight || effBottom > effTop) {
if (effLeft > effRight || effTop > effBottom) {
System.out.println("内缩后无有效空间,返回空路径");
return new ArrayList<>();
}
@ -72,10 +72,10 @@ public class PathGenerator {
// 2) 根据mode选择不同的之字形算法
return switch (mode) {
case HORIZONTAL_ZIGZAG_TOP_DOWN -> generateHorizontalZigzagTopDown(
effLeft, effRight, effBottom, effTop, spacing
effLeft, effRight, effTop, effBottom, spacing
);
case VERTICAL_ZIGZAG_LEFT_RIGHT -> generateVerticalZigzagLeftRight(
effLeft, effRight, effBottom, effTop, spacing
effLeft, effRight, effTop, effBottom, spacing
);
default ->
// 预留给更多模式扩展
@ -84,20 +84,20 @@ public class PathGenerator {
}
/**
* [effLeft..effRight] x [effBottom..effTop] 区域内
* [effLeft..effRight] x [effTop..effBottom] 区域内
* (左上)开始水平之字形向下扫描
* 流程
* 1) 第1行 (effLeft, effTop) -> (effRight, effTop)
* 2) 下移 spacing
* 3) 第2行 (effRight, effTop - spacing) -> (effLeft, effTop - spacing)
* 3) 第2行 (effRight, effTop + spacing) -> (effLeft, effTop + spacing)
* 4) 下移 spacing
* 重复直到无法再下移
*/
private static List<Point> generateHorizontalZigzagTopDown(
int effLeft,
int effRight,
int effBottom,
int effTop,
int effBottom,
int spacing
) {
List<Point> result = new ArrayList<>();
@ -118,8 +118,8 @@ public class PathGenerator {
result.add(new Point(currentX, currentY));
// 往下移动 spacing
int nextY = currentY - spacing;
if (nextY < effBottom) {
int nextY = currentY + spacing;
if (nextY > effBottom) {
break; // 无法再往下
}
currentY = nextY;
@ -132,7 +132,7 @@ public class PathGenerator {
}
/**
* [effLeft..effRight] x [effBottom..effTop] 区域内
* [effLeft..effRight] x [effTop..effBottom] 区域内
* (左上)开始垂直之字形向右扫描
* <p>
* 流程
@ -145,8 +145,8 @@ public class PathGenerator {
private static List<Point> generateVerticalZigzagLeftRight(
int effLeft,
int effRight,
int effBottom,
int effTop,
int effBottom,
int spacing
) {
List<Point> result = new ArrayList<>();
@ -183,13 +183,13 @@ public class PathGenerator {
// ============= 简单测试 =============
public static void main(String[] args) {
int left = 0, right = 10;
int bottom = 0, top = 6;
int top = 0, bottom = 6;
int spacing = 2;
// 1) 测试水平之字形(从上往下)
System.out.println("=== HORIZONTAL_ZIGZAG_TOP_DOWN ===");
List<Point> horizontalPath = generatePathPoints(
left, right, bottom, top, spacing, MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN
left, right, top, bottom, spacing, MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN
);
for (Point p : horizontalPath) {
System.out.println(p);
@ -198,11 +198,10 @@ public class PathGenerator {
// 2) 测试垂直之字形(从左往右)
System.out.println("\n=== VERTICAL_ZIGZAG_LEFT_RIGHT ===");
List<Point> verticalPath = generatePathPoints(
left, right, bottom, top, spacing, MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT
left, right, top, bottom, spacing, MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT
);
for (Point p : verticalPath) {
System.out.println(p);
}
}
}
}

56
src/main/java/com/qyft/ms/app/common/generator/RectangleGrid.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;
}
}

26
src/main/java/com/qyft/ms/app/controller/CMDController.java

@ -41,7 +41,7 @@ public class CMDController {
if (cmdService.moveMotorToPosition(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -64,7 +64,7 @@ public class CMDController {
if (cmdService.switchThreeWayValve(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -87,7 +87,7 @@ public class CMDController {
if (cmdService.controlValve(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -110,7 +110,7 @@ public class CMDController {
if (cmdService.turnOnHighVoltage(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -133,7 +133,7 @@ public class CMDController {
if (cmdService.turnOffHighVoltage(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -156,7 +156,7 @@ public class CMDController {
if (cmdService.turnOnSyringePump(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -179,7 +179,7 @@ public class CMDController {
if (cmdService.turnOffSyringePump(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -199,10 +199,10 @@ public class CMDController {
cmdForm.setCommandName("startWork");
}
log.info("接收到指令: {}", JSONUtil.toJsonStr(cmdForm));
if (cmdService.startWork(cmdForm)) {
if(Objects.equals(cmdService.startWork(cmdForm), "ok")) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
}else {
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -225,7 +225,7 @@ public class CMDController {
if (cmdService.stopWork(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -248,7 +248,7 @@ public class CMDController {
if (cmdService.setMotorRunningCurrent(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);
@ -271,7 +271,7 @@ public class CMDController {
if (cmdService.rotate(cmdForm)) {
return Result.success(cmdForm.getCommandId());
} else {
return Result.failed("无效命令");
return Result.failed("参数错误");
}
} catch (Exception e) {
log.error("指令执行异常: {}", JSONUtil.toJsonStr(cmdForm), e);

8
src/main/java/com/qyft/ms/app/controller/MatrixCraftController.java

@ -2,8 +2,8 @@ package com.qyft.ms.app.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qyft.ms.app.model.dto.MatrixCraftDTO;
import com.qyft.ms.app.model.entity.Matrix;
import com.qyft.ms.app.model.entity.MatrixCraft;
import com.qyft.ms.app.model.vo.MatrixCraftResult;
import com.qyft.ms.app.service.MatrixCraftService;
import com.qyft.ms.system.common.base.BasePageQuery;
import com.qyft.ms.system.common.result.PageResult;
@ -53,9 +53,9 @@ public class MatrixCraftController {
@Operation(summary = "所有工艺列表")
@GetMapping("/list")
public PageResult<MatrixCraft> getAll(BasePageQuery pageQuery) {
IPage<MatrixCraft> result = matrixCraftService.page(new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()), null);
return PageResult.success(result);
public PageResult<MatrixCraftResult> getAll(BasePageQuery pageQuery) {
// IPage<MatrixCraft> result = matrixCraftService.page(new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()), null);
return PageResult.success(matrixCraftService.getAll(pageQuery));
}
@Operation(summary = "基质工艺更新")

11
src/main/java/com/qyft/ms/app/model/vo/MatrixCraftResult.java

@ -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;
}

57
src/main/java/com/qyft/ms/app/service/CMDService.java

@ -41,6 +41,9 @@ public class CMDService {
// 电机移动
public boolean moveMotorToPosition(CMDForm form) {
Map<String, Object> params = form.getParams();
if (params == null || !params.containsKey("axis") || !params.containsKey("position")) {
return false;
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
String axis = (String) params.get("axis");
double position = Optional.ofNullable(params.get("position"))
@ -56,12 +59,17 @@ public class CMDService {
// 切换清洗管路/喷涂管路
public boolean switchThreeWayValve(CMDForm form) {
Map<String, Object> params = form.getParams();
if (params == null || !params.containsKey("type")) {
return false;
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
String type = (String) params.get("type");
if (type.equals("clean")) {
cmdList.add(deviceTcpCMDService::switchThreeWayValveToSubstrate);
} else if (type.equals("spray")) {
cmdList.add(deviceTcpCMDService::switchThreeWayValveToSpray);
}else {
return false;
}
initExecutorThread(cmdList, form);
return true;
@ -70,6 +78,9 @@ public class CMDService {
// 除湿阀清洗阀喷嘴阀控制方法
public boolean controlValve(CMDForm form) {
Map<String, Object> params = form.getParams();
if (params == null || !params.containsKey("valveType") || !params.containsKey("isOpen")) {
return false;
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
if(params.get("valveType") !=null && params.get("isOpen") !=null) {
String valveType = (String) params.get("valveType");
@ -83,6 +94,9 @@ public class CMDService {
// 以指定电压值开启高压电
public boolean turnOnHighVoltage(CMDForm form) {
Map<String, Object> params = form.getParams();
if (params == null || !params.containsKey("voltage")) {
return false;
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
double voltage = Optional.ofNullable(params.get("voltage"))
.filter(Number.class::isInstance)
@ -97,6 +111,9 @@ public class CMDService {
// 关闭高压电
public boolean turnOffHighVoltage(CMDForm form) {
Map<String, Object> params = form.getParams();
if (params == null) {
return false;
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
cmdList.add(deviceTcpCMDService::turnOffHighVoltage);
initExecutorThread(cmdList, form);
@ -106,6 +123,9 @@ public class CMDService {
// 以指定转速方向和时间开启注射泵
public boolean turnOnSyringePump(CMDForm form) {
Map<String, Object> params = form.getParams();
if (params == null || !params.containsKey("rotationSpeed") || !params.containsKey("time") || !params.containsKey("direction")) {
return false;
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
double rotationSpeed = Optional.ofNullable(params.get("rotationSpeed"))
.filter(Number.class::isInstance)
@ -126,6 +146,9 @@ public class CMDService {
// 停止注射泵
public boolean turnOffSyringePump(CMDForm form) {
Map<String, Object> params = form.getParams();
if (params == null) {
return false;
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
cmdList.add(deviceTcpCMDService::turnOffSyringePump);
initExecutorThread(cmdList, form);
@ -135,6 +158,9 @@ public class CMDService {
// 设置指定轴的电机运行时电流
public boolean setMotorRunningCurrent(CMDForm form) {
Map<String, Object> params = form.getParams();
if (params == null || !params.containsKey("axis") || !params.containsKey("current")) {
return false;
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
String axis = (String) params.get("axis");
double current = Optional.ofNullable(params.get("current"))
@ -148,20 +174,32 @@ public class CMDService {
}
// 开始喷涂
public boolean startWork(CMDForm form) {
public String startWork(CMDForm form) {
Map<String, Object> params = form.getParams();
if (
params == null ||
!params.containsKey("position") ||
!params.containsKey("space") ||
!params.containsKey("routeType") ||
!params.containsKey("movementSpeed") ||
!params.containsKey("height") ||
!params.containsKey("matrixFlowVelocity") ||
!params.containsKey("matrixCraftId")
) {
return "参数错误";
}
List<Supplier<Boolean>> cmdList = new ArrayList<>();
// 托盘位置
List<SysSettings> slidePositionList = sysSettingsService.getSlidePositionList();
List<Map<String, Integer>> position = (List<Map<String, Integer>>) params.get("position");
if (position == null) {
throw new RuntimeException("position参数错误");
return "position参数错误";
}
for (int i = 0; i < position.size(); i++) {
Map<String, Integer> p = position.get(i);
if (p.get("x1") == null || p.get("y1") == null || p.get("x2") == null || p.get("y2") == null || p.get("index") == null) {
throw new RuntimeException("position参数错误");
return "position参数错误";
}
// 玻片的位置
String p1 = slidePositionList.get(p.get("index")).getValue();
@ -178,10 +216,14 @@ public class CMDService {
int bottom = y+ p.get("y2");
int space = (Integer) params.get("space");
int direction = (Integer) params.get("direction");
int routeType = (Integer) params.get("routeType");
List<Point> horizontalPath = generatePathPoints(
left, right, bottom, top, space, direction == 1 ? PathGenerator.MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN : PathGenerator.MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT
left, right, top, bottom, space, routeType == 1 ? PathGenerator.MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN : PathGenerator.MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT
);
log.info("horizontalPath:{}", horizontalPath);
if(horizontalPath.isEmpty()) {
return "路径规划失败";
}
// 将三通阀转至喷涂管路
cmdList.add(deviceTcpCMDService::switchThreeWayValveToSpray);
@ -247,12 +289,11 @@ public class CMDService {
return true;
});
initExecutorThread(cmdList, form);
return true;
return "ok";
}
// 结束喷涂
public boolean stopWork(CMDForm form) {
Map<String, Object> params = form.getParams();
List<Supplier<Boolean>> cmdList = new ArrayList<>();
// 停止喷涂
cmdList.add(deviceTcpCMDService::turnOffSyringePump);
@ -282,7 +323,7 @@ public class CMDService {
}
private void run(List<Supplier<Boolean>> cmdList, CMDForm form) {
public void run(List<Supplier<Boolean>> cmdList, CMDForm form) {
ExecutionResult executionResult = new ExecutionResult();
executionResult.setCommandId(form.getCommandId());
executionResult.setCommandName(form.getCommandName());

5
src/main/java/com/qyft/ms/app/service/MatrixCraftService.java

@ -1,8 +1,11 @@
package com.qyft.ms.app.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.qyft.ms.app.model.dto.MatrixCraftDTO;
import com.qyft.ms.app.model.entity.MatrixCraft;
import com.qyft.ms.app.model.vo.MatrixCraftResult;
import com.qyft.ms.system.common.base.BasePageQuery;
import java.util.List;
@ -22,4 +25,6 @@ public interface MatrixCraftService extends IService<MatrixCraft> {
Boolean updateMatrixCraft(MatrixCraft matrixCraft);
Boolean deleteMatrixCraft(String ids);
IPage<MatrixCraftResult> getAll(BasePageQuery pageQuery);
}

3
src/main/java/com/qyft/ms/app/service/WebSocketService.java

@ -4,10 +4,13 @@ import cn.hutool.json.JSONUtil;
import com.qyft.ms.app.config.WebSocketServer;
import com.qyft.ms.app.model.vo.WebsocketResult;
import jakarta.annotation.PostConstruct;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@Profile("!test")
@Service
public class WebSocketService {
public void pushMsg(String type, Object result) {
WebsocketResult websocketResult = new WebsocketResult();

2
src/main/java/com/qyft/ms/app/service/impl/ISysSettingsServiceImpl.java

@ -30,7 +30,7 @@ public class ISysSettingsServiceImpl extends ServiceImpl<SysSettingsMapper, SysS
public void init() {
QueryWrapper<SysSettings> queryWrapper = new QueryWrapper<>();
queryWrapper.in("code", "slide_position");
Long parentId = sysSettingsMapper.selectOne(queryWrapper).getParentId();
Long parentId = sysSettingsMapper.selectOne(queryWrapper).getId();
slidePositionList = sysSettingsMapper.selectList(new QueryWrapper<SysSettings>().eq("parent_id", parentId));
motorSpeedList = sysSettingsMapper.selectList(new QueryWrapper<SysSettings>().eq("parent_id", new QueryWrapper<SysSettings>().eq("code", "speed")));
}

31
src/main/java/com/qyft/ms/app/service/impl/MatrixCraftServiceImpl.java

@ -1,13 +1,24 @@
package com.qyft.ms.app.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qyft.ms.app.mapper.MatrixCraftMapper;
import com.qyft.ms.app.mapper.MatrixMapper;
import com.qyft.ms.app.model.dto.MatrixCraftDTO;
import com.qyft.ms.app.model.entity.Matrix;
import com.qyft.ms.app.model.entity.MatrixCraft;
import com.qyft.ms.app.model.entity.OperationLog;
import com.qyft.ms.app.model.vo.MatrixCraftResult;
import com.qyft.ms.app.service.MatrixCraftService;
import com.qyft.ms.app.service.MatrixService;
import com.qyft.ms.system.common.base.BasePageQuery;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@ -19,6 +30,7 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class MatrixCraftServiceImpl extends ServiceImpl<MatrixCraftMapper, MatrixCraft> implements MatrixCraftService {
private final MatrixCraftMapper matrixCraftMapper;
private final MatrixMapper matrixMapper;
@Override
public Integer add(MatrixCraftDTO dto) {
return matrixCraftMapper.add(dto);
@ -46,4 +58,23 @@ public class MatrixCraftServiceImpl extends ServiceImpl<MatrixCraftMapper, Matri
.collect(Collectors.toList());
return this.removeByIds(idsArr);
}
@Override
public IPage<MatrixCraftResult> getAll(BasePageQuery pageQuery) {
// 构建分页对象
Page<MatrixCraftResult> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());
ArrayList<MatrixCraftResult> matrixCraftResultList = new ArrayList<>();
// 查询所有工艺
List<MatrixCraft> matrixCrafts = matrixCraftMapper.selectList(new QueryWrapper<>());
for (MatrixCraft matrixCraft : matrixCrafts) {
Long matrixId = matrixCraft.getMatrixId();
Matrix matrix = matrixMapper.selectOne(new QueryWrapper<Matrix>().eq("id", matrixId));
MatrixCraftResult matrixCraftResult = new MatrixCraftResult();
BeanUtils.copyProperties(matrixCraft, matrixCraftResult);
matrixCraftResult.setMatrixName(matrix.getName());
matrixCraftResultList.add((matrixCraftResult));
}
page.setRecords(matrixCraftResultList);
return page;
}
}

2
src/main/resources/application.yml

@ -35,7 +35,7 @@ jwt:
#与设备TCP链接
tcp:
enable: true # 是否开启 TCP 连接
host: 192.168.1.130
host: 192.168.1.140
port: 9080
reconnect: 5000 # 断线重连间隔(单位:毫秒)
timeout: 10000 # 连接超时时间(单位:毫秒)

144
src/test/java/com/qyft/ms/CMDServiceTest.java

@ -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));
}
}

111
src/test/java/com/qyft/ms/SprayTest.java

@ -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测试通过!");
}
}
Loading…
Cancel
Save