还在为手动编写测试用例秃头吗?面对复杂需求文档,一个一个抠测试点,不仅效率低,还容易遗漏关键场景?为了解决该问题,笔者依托Spring AI开发了测试用例生成工具~
 
 
 
 
 核心功能
  • 全类型文档分析:基于 Spring AI Alibaba的自然语言处理和图像识别能力,支持pdf 、word、txt多种格式需求文档,精准提取需求点。​
  • 智能生成与筛选:采用 Spring AI Alibaba的生成者评估者模式,生成者批量产出候选测试用例,评估者从合理性、覆盖率等维度筛选,保障用例质量与全面性。​
  • 脑图可视化呈现:将生成的测试用例自动转化为表格和脑图,清晰展示用例逻辑结构和与需求的对应关系,方便理解、执行与团队协作。​
️ 技术架构
  • 底层框架:依托 Spring AI Alibaba,实现对文档的智能解析与处理。​
  • 生成模式:运用生成者评估者模式,构建高效可靠的测试用例生成流程。​
  • 可视化:集成表格和脑图生成技术,让测试用例以直观图形化方式呈现。

代码整体框架:

代码详解:

1. 常量定义(Consts.java)

package com.fingertip.caseaibackend.commons;

public class Consts {
public static final String ANALYZE_PROMPT = ...;
public static final String CASE_WRITER_PROMPT = ...;
public static final String CASE_REVIEWER_PROMPT = ...;
public static final String CASE_FORMAT_PROMPT = ...;
public static final String VISUAL_PROMPT = ...; public static final String ORIGIN_MESSAGE = "originMessage";
public static final String CASE_INFO_MESSAGE = "caseInfoMessage";
public static final String CASE_REVIEW_MESSAGE = "caseReviewMessage";
public static final String CASE_FORMAT_MESSAGE = "caseFormatMessage";
}

该类定义了一系列常量,包括与大语言模型交互时使用的提示信息(如需求分析提示、测试用例编写提示等)以及状态图中使用的消息键。

2. 配置文件(application.yml)

server:
port: 8080 spring:
application:
name: spring-ai-alibaba-openai-chat-model-example
ai:
openai:
api-key: xxx
base-url: https://api.siliconflow.cn/
chat:
options:
model: deepseek-ai/DeepSeek-R1
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
case-model:
visual:
api-key: xxx
base-url: https://api.siliconflow.cn/
model: Qwen/Qwen2.5-VL-72B-Instruct
analyze:
api-key: xxx
base-url: https://api.siliconflow.cn/
model: deepseek-ai/DeepSeek-R1
generate:
api-key: xxx
base-url: https://api.siliconflow.cn/
model: deepseek-ai/DeepSeek-R1-Distill-Qwen-7B
reviewer:
api-key: xxx
base-url: https://api.siliconflow.cn/
model: MiniMaxAI/MiniMax-M1-80k
format:
api-key: xxx
base-url: https://api.siliconflow.cn/
model: deepseek-ai/DeepSeek-V3
logging:
level:
root: INFO
org.springframework.ai: DEBUG
com.example.demo: DEBUG

配置文件定义了服务器端口、Spring AI 的基本配置(如 API 密钥、基础 URL、模型类型)以及不同任务(如可视化、需求分析、测试用例生成等)使用的模型信息。同时,还配置了文件上传的最大大小和日志级别。

3. 大语言模型配置(LLMConfig.java)

package com.fingertip.caseaibackend.aiproxies.configs;

import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class LLMConfig {
@Value("${case-model.analyze.api-key}")
private String analyze_apiKey = "";
@Value("${case-model.analyze.base-url}")
private String analyze_baseUrl = "";
@Value("${case-model.analyze.model}")
private String analyze_Model = ""; @Bean
public ChatModel analyzeModel() {
OpenAiChatOptions options = new OpenAiChatOptions();
options.setModel(analyze_Model);
options.setTemperature(0.7);
return OpenAiChatModel.builder().openAiApi(OpenAiApi.builder().apiKey(analyze_apiKey).baseUrl(analyze_baseUrl).build()).defaultOptions(options).build();
} // 其他模型配置...
}

该类使用 Spring 的 @Configuration 注解,通过 @Value 注解从配置文件中读取不同任务所需的 API 密钥、基础 URL 和模型类型,然后创建相应的 ChatModel 实例。

4. 控制器(AiChatController.java)

@RestController
@RequestMapping("/ai-api")
public class AiChatController {
private static final String DEFAULT_PROMPT = "你好,介绍下你自己!"; private final ChatClient openAiAnalyzeChatClient;
private final ChatClient openAiGenerateChatClient;
private final ChatClient openAiReviewerChatClient;
private final ChatClient openAiFormatChatClient;
private final ChatClient openAiVisualChatClient; public AiChatController(@Qualifier("analyzeModel") ChatModel analyzeModel, ...) {
this.openAiAnalyzeChatClient = ChatClient.builder(analyzeModel)
.defaultAdvisors(new SimpleLoggerAdvisor())
.defaultOptions(OpenAiChatOptions.builder().topP(0.7).build())
.build();
// 其他 ChatClient 初始化...
} @PostMapping("/file/upload")
public ApiResult<String> uploadFile(@RequestParam("files") MultipartFile[] files) {
ApiResult<String> result = new ApiResult<>();
try {
if (files == null || files.length == 0) {
result.setMessage("上传文件为空");
result.setCode(400);
return result;
} StringBuilder contentBuilder = new StringBuilder();
for (MultipartFile file : files) {
if (file.isEmpty()) {
continue;
}
String fileName = file.getOriginalFilename();
if (fileName == null) {
continue;
} if (fileName.endsWith(".docx") || fileName.endsWith(".pdf")) {
List<Media> mediaList = null;
if (fileName.endsWith(".docx")) {
// 将 docx 转换为 PDF
XWPFDocument docxDoc = new XWPFDocument(file.getInputStream());
ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream();
PdfOptions options = PdfOptions.create();
PdfConverter.getInstance().convert(docxDoc, pdfOutputStream, options);
byte[] pdfBytes = pdfOutputStream.toByteArray();
mediaList = convertPdfToImages(pdfBytes);
} else if (fileName.endsWith(".pdf")) {
mediaList = convertPdfToImages(file.getBytes());
}
if (mediaList != null && !mediaList.isEmpty()) {
UserMessage message = UserMessage.builder().text(Consts.VISUAL_PROMPT).media(mediaList).metadata(new HashMap<>()).build();
message.getMetadata().put(MESSAGE_FORMAT, MessageFormat.IMAGE);
String content = openAiVisualChatClient.prompt(new Prompt(message)).call().content();
contentBuilder.append(content).append("\n");
}
} else {
if (!file.isEmpty()) {
contentBuilder.append(file.getOriginalFilename()).append(":\n");
contentBuilder.append(new String(file.getBytes(), StandardCharsets.UTF_8)).append("\n");
}
}
}
String content = contentBuilder.toString(); String resp = openAiAnalyzeChatClient
.prompt(Consts.ANALYZE_PROMPT)
.user(content)
.call()
.content(); result.setData(resp);
result.setMessage("解析完成");
result.setCode(200);
} catch (Exception e) {
result.setMessage("文件处理异常: " + e.getMessage());
result.setCode(500);
return result;
}
return result;
} // 其他接口方法...
}

AiChatController 是项目的控制器类,负责处理客户端的请求。它通过构造函数注入不同任务的 ChatClient 实例,提供了文件上传、流式文件上传和测试用例创建等接口。在文件上传接口中,会根据文件类型(.docx 或 .pdf)进行相应的处理,如将 docx 转换为 PDF,再将 PDF 转换为图片,最后调用可视化模型进行处理

5. 节点类(CaseGenerateNode.java, CaseReviewerNode.java, CaseFormatNode.java)

package com.fingertip.caseaibackend.aiproxies.nodes;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.fingertip.caseaibackend.commons.Consts;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.util.StringUtils; import java.util.HashMap;
import java.util.Map; public class CaseGenerateNode implements NodeAction {
private final ChatClient chatClient; public CaseGenerateNode(ChatClient chatClient) {
this.chatClient = chatClient;
} @Override
public Map<String, Object> apply(OverAllState t) {
String origin_message = (String) t.value(Consts.ORIGIN_MESSAGE).orElse("");
String case_reviewer_message = (String) t.value(Consts.CASE_REVIEW_MESSAGE).orElse("");
String caseInfo = (String) t.value(Consts.CASE_INFO_MESSAGE).orElse(""); if (!StringUtils.hasText(origin_message)) {
throw new IllegalArgumentException("没有找到原始消息");
}
String content = Consts.CASE_WRITER_PROMPT + "\n\n" + origin_message;
if (StringUtils.hasText(case_reviewer_message) && StringUtils.hasText(caseInfo)) {
content = "%s\n# 原始需求:\n%s\n\n# 上个版本需求用例:\n%s \n# 专家意见:%s\n".formatted(Consts.CASE_WRITER_PROMPT, origin_message, caseInfo, case_reviewer_message);
} ChatResponse response = chatClient.prompt(content).call().chatResponse();
String output = null;
if (response != null) {
output = response.getResult().getOutput().getText();
} Map<String, Object> updated = new HashMap<>();
updated.put(Consts.CASE_INFO_MESSAGE, output); return updated;
}
}

这些节点类实现了 NodeAction 接口,用于在状态图中执行特定的任务。例如,CaseGenerateNode 负责根据原始需求和评审意见生成测试用例,它从 OverAllState 中获取所需的信息,构造请求内容,调用相应的 ChatClient 与大语言模型交互,最后将生成的测试用例信息存储到 OverAllState 中。

6. 反馈分发器(FeedbackDispatcher.java)

package com.fingertip.caseaibackend.aiproxies.nodes;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.EdgeAction;
import com.fingertip.caseaibackend.commons.Consts; public class FeedbackDispatcher implements EdgeAction {
@Override
public String apply(OverAllState t) {
String output = (String) t.value(Consts.CASE_REVIEW_MESSAGE).orElse("");
return output.toLowerCase().contains("approve") ? "positive" : "negative";
}
}

FeedbackDispatcher 实现了 EdgeAction 接口,根据测试用例评审结果(CASE_REVIEW_MESSAGE)判断是否通过评审,并返回相应的反馈结果(positive 或 negative),用于状态图中的流程控制

C端页面

总结:

目前用例生成的promot需持续调优,测试用例的补全、最终用例的存储、下载功能有待开发,敬请期待~

Spring AI Alibaba智能测试用例生成的更多相关文章

  1. AI中台——智能聊天机器人平台的架构与应用(分享实录)

    内容来源:宜信技术学院第3期技术沙龙-线上直播|AI中台——智能聊天机器人平台 主讲人:宜信科技中心AI中台团队负责人王东 导读:随着“中台”战略的提出,目前宜信中台建设在思想理念及架构设计上都已经取 ...

  2. Spring Cloud Alibaba基础教程:Sentinel Dashboard同步Apollo存储规则

    在之前的两篇教程中我们分别介绍了如何将Sentinel的限流规则存储到Nacos和Apollo中.同时,在文末的思考中,我都指出了这两套整合方案都存在一个不足之处:不论采用什么配置中心,限流规则都只能 ...

  3. Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Apollo

    在之前的两篇教程中我们分别介绍了如何将Sentinel的限流规则存储到Nacos和Apollo中.同时,在文末的思考中,我都指出了这两套整合方案都存在一个不足之处:不论采用什么配置中心,限流规则都只能 ...

  4. Spring Cloud Alibaba微服务生态的基础实践

    目录 一.背景 二.初识Spring Cloud Alibaba 三.Nacos的基础实践 3.1 安装Nacos并启动服务 3.2 建立微服务并向Nacos注册服务 3.3 建立微服务消费者进行服务 ...

  5. Spring Cloud Alibaba系列之分布式服务组件Dubbo

    本博客的例子代码可以在github找到下载链接:代码下载 SpringBoot.SpringCloud Alibaba系列博客专栏:链接 1.分布式理论 1.1.分布式基本定义 <分布式系统原理 ...

  6. 时序扩展的UML状态图的测试用例生成研究

    一.基本信息 标题:时序扩展的UML状态图的测试用例生成研究 时间:2014 出版源:西南大学 领域分类:时序扩展:UML状态图:测试用例:需求规格说明:模型 二.研究背景 问题定义:时序扩展的UML ...

  7. Spring Cloud Alibaba Sentinel 整合 Feign 的设计实现

    作者 | Spring Cloud Alibaba 高级开发工程师洛夜 来自公众号阿里巴巴中间件投稿 前段时间 Hystrix 宣布不再维护之后(Hystrix 停止开发...Spring Cloud ...

  8. 【星云测试】Wings-让单元测试智能全自动生成

    Wings-让单元测试智能全自动生成 前言 单元测试是保证软件质量非常有效的手段,无论是从测试理论早期介入测试的理念来看或是从单元测试不受UI影响可以高速批量验证的特性,所以业界所倡导的测试驱动开发, ...

  9. Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Nacos

    上一篇我们介绍了如何通过改造Sentinel Dashboard来实现修改规则之后自动同步到Apollo.下面通过这篇,详细介绍当使用Nacos作为配置中心之后,如何实现Sentinel Dashbo ...

  10. Spring Cloud Alibaba | 序言

    目录 Spring Cloud Alibaba | 序言 1. Spring Cloud Alibaba是什么? 2. 主要功能 3. 组件 4. 版本说明 4.1 版本依赖关系 4.2 组件版本关系 ...

随机推荐

  1. Windows 左ctrl和左alt键互换

    reg代码 Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyb ...

  2. PHP传递参数(跨文件)的8种常见方法

    以下是 PHP 中跨文件传递参数的 8 种常见方法,按场景和安全性分类整理,附详细说明和示例代码: 一.超全局变量(适合请求间数据共享) 1. $_GET / $_POST 用途:通过 URL 或表单 ...

  3. Sa-Token v1.42.0 发布 🚀,新增 API Key、TOTP 验证码、RefreshToken 反查等能力

    Sa-Token 是一款 免费.开源 的轻量级 Java 权限认证框架,主要解决:登录认证.权限认证.单点登录.OAuth2.0.微服务网关鉴权 等一系列权限相关问题. 目前最新版本 v1.42.0 ...

  4. Java提交到MySQL数据库出现中文乱码

    1)使用文本或者链接地址写到代码中(不推荐)时,实例如下: jdbc:mysql://localhost:3306/tms?useUnicode=true&characterEncoding= ...

  5. python调用百度ocr接口,实现图片内文字识别

    第一步,到百度智能云申请接口资源 打开地址:https://cloud.baidu.com/?from=console,点击产品下的通用场景文字识别 立即使用,跳转页领取免费资源(土豪可直接购买) 选 ...

  6. 里程碑:MCP星球作为国内首个中文MCP社区和MCP工具平台,突破7000个MCP服务!

    随着人工智能技术的快速发展,越来越多的开发者开始使用模型上下文协议(Model Context Protocol,简称MCP)来优化大模型与外部工具的交互.作为首个最大的中文MCP工具市场,MCP星球 ...

  7. thinkphphp 计算分页 和分页总数 和sql计算分页 php

    利用page计算分页 $p=input('p')?input('p'):1; $limit=6; $res=db('points_log')->where(['p_uid'=>$uid,' ...

  8. 小白也能行【手撕ResNet代码篇(附代码)】:详解可复现

    目录 前言 model BasicBlock 和Bottleneck ResNet ResNet18\34\50\101\152 data train test 代码运行以及测试结果 前言 之前已经给 ...

  9. 开源PDF处理工具——Ghostscript的安装和使用

    1. 安装 Ghostscript Windows 下载 Ghostscript: 官网:https://www.ghostscript.com/download/gsdnld.html 选择适合你的 ...

  10. CF1930G Prefix Max Set Counting 题解

    题意: 给定一棵以 1 为根的有根树,求出其所有 dfs 序中前缀最大值序列的数量.\(n\le 10^6\). 思路 显然考虑 DP. 由于是求前缀最大值序列的方案数,因此如果一些点要出现在这个序列 ...