当前位置: 首页 > news >正文

KART-RERANK与软件测试结合:自动化生成测试用例的优先级排序

KART-RERANK与软件测试结合:自动化生成测试用例的优先级排序

你是不是也遇到过这种情况?项目急着上线,测试团队却对着成千上万个自动化测试用例发愁。全部跑一遍?时间根本不够。挑着跑?又怕漏掉关键的Bug。这种“测不完”和“测不准”的矛盾,几乎是每个软件团队的日常痛点。

最近,我们团队尝试了一种新思路,把原本用在搜索推荐里的KART-RERANK模型,搬到了软件测试的战场上。简单来说,就是让AI来帮我们判断:在代码刚改完、时间又紧张的时候,应该先跑哪些测试用例,才能最快地发现潜在问题。试运行了一段时间,效果还挺让人惊喜的。

这篇文章,我就来聊聊我们是怎么做的,以及它到底解决了哪些实际问题。

1. 软件测试的“选择困难症”

在聊技术方案之前,我们先看看问题到底出在哪。现代软件开发,尤其是采用了敏捷或DevOps流程的团队,代码变更非常频繁。每次提交新代码,都需要运行相关的自动化测试来确保质量。但现实往往很骨感。

1.1 测试资源的瓶颈

理想情况下,每次代码提交都应该触发完整的回归测试套件。但动辄数万甚至数十万的测试用例,跑一次可能需要几个小时甚至几天。这对于追求快速迭代的团队来说,是完全无法接受的。于是,大家只能妥协:要么只跑一部分测试,要么延长测试等待时间。前者带来了漏测风险,后者则拖慢了开发节奏。

1.2 传统优先级排序的局限

为了解决这个问题,测试领域早就有了“测试用例优先级排序”的概念。传统方法主要依赖几种策略:

  • 基于覆盖率的排序:优先执行覆盖了最新修改代码的测试。
  • 基于历史的排序:优先执行历史上发现Bug较多的测试。
  • 随机或人工指定:这就不用多说了,基本靠感觉。

这些方法各有各的问题。基于覆盖率的方法,需要精确的代码覆盖分析工具,而且它假设“覆盖了修改代码的测试更容易发现问题”,这个假设并不总是成立。基于历史的方法则过于依赖过去的数据,对于新代码或历史数据稀少的模块就不太灵了。

最根本的问题是,这些方法都是“单维度”思考。而一个测试用例是否容易发现问题,其实是由代码变更内容、模块历史缺陷密度、开发人员习惯、甚至提交时间等多个因素共同决定的。这就需要一种更“智能”的排序方式。

2. KART-RERANK模型:从“搜索排序”到“测试排序”

KART-RERANK这个名字听起来有点技术化,但它的核心思想并不复杂。它最初被设计用来解决搜索和推荐系统中的“重排序”问题。比如,搜索引擎先找到一堆相关文档,再用更复杂的模型对这批文档进行精细排序,把最可能满足用户需求的排在最前面。

我们发现,这个场景和我们的测试用例排序问题惊人地相似:

  1. 都有候选集:搜索引擎有一堆相关文档,我们有一堆相关的测试用例(比如所有覆盖了修改文件的用例)。
  2. 都需要精细排序:搜索引擎要把最好的结果排前面,我们要把最可能发现Bug的测试用例排前面。
  3. 都依赖多维度特征:搜索排序看点击率、停留时间、内容质量等;测试排序则可以看代码变更、历史缺陷、执行时间等。

2.1 模型的核心思路

KART-RERANK模型通常不直接从海量候选集中筛选,而是接收一个“粗排”阶段提供的、规模较小的候选列表,然后利用更丰富的特征和更复杂的模型进行重新打分和排序。把它迁移到测试领域,工作流程就变成了:

  1. 粗排(检索阶段):根据本次代码提交所修改的文件,快速找出所有与之相关的测试用例。这一步可以用简单的代码静态分析工具完成,速度很快。
  2. 精排(重排序阶段):对粗排得到的测试用例列表,使用KART-RERANK模型进行打分。模型会综合考量每个测试用例的多种特征,预测其“发现本次提交引入缺陷的概率”。
  3. 输出与执行:按照模型打分从高到低排序,生成最终的测试执行队列。测试资源(如执行机、时间)有限时,就优先执行队列前面的测试。

这个过程的巧妙之处在于,它把复杂的全局排序问题,分解成了“快速检索”加“精准排序”两个步骤,在保证效果的同时兼顾了效率。

2.2 我们需要哪些特征?

模型的好坏,很大程度上取决于你喂给它什么样的特征。在测试排序场景下,我们主要构建了以下几类特征:

  • 代码变更特征:这是最直接的信号。包括修改了哪些文件、哪些函数、修改的类型(是新增、删除还是修改)、修改的代码行数、变更的代码复杂度等。一个测试用例如果覆盖了被修改的核心函数,它的优先级自然应该提高。
  • 历史缺陷特征:体现模块的“脆弱性”。包括被修改文件的历史缺陷数量、缺陷密度(缺陷数/代码行)、最近是否频繁出Bug、关联测试用例的历史失败率等。一个“黑历史”很多的模块,其相关的测试用例需要更严格的审查。
  • 测试用例自身特征:体现测试的“效力”。包括用例的执行时间、上次执行是否通过、历史发现缺陷的数量、测试的代码覆盖率深度(如分支覆盖、条件覆盖)等。一个又慢又从来没发现过Bug的测试,优先级可以适当放后。
  • 开发上下文特征:一些软性指标。比如代码提交者的历史提交质量、提交时间(是否在深夜匆忙提交)、提交日志的规范性等。这些特征可以作为辅助判断。

把这些特征组合起来,就构成了一个描述“本次代码提交”与“某个测试用例”相关性的多维向量。KART-RERANK模型的任务,就是学习这个向量与“测试能否发现Bug”这个结果之间的复杂关系。

3. 实战:搭建智能测试排序流水线

理论说得再多,不如看看实际怎么落地。下面我分享一下我们构建这个智能排序流水线的关键步骤和示例代码。整个流程可以集成在CI/CD平台(如Jenkins、GitLab CI)中,在代码提交后自动触发。

3.1 第一步:数据收集与特征工程

一切的基础是数据。我们需要从代码仓库、缺陷管理系统、测试管理平台等地方收集历史数据。

# 示例:一个简单的特征提取函数 import git from datetime import datetime, timedelta def extract_features_for_test(test_case_id, commit_hash): """ 为某个测试用例和某次提交提取特征向量。 """ features = {} # 1. 代码变更特征 repo = git.Repo('/path/to/your/repo') commit = repo.commit(commit_hash) modified_files = [item.a_path for item in commit.diff('HEAD~1')] # 假设我们有函数能获取测试用例覆盖的文件 test_covered_files = get_covered_files_by_test(test_case_id) # 计算交集相关度 features['files_intersection_ratio'] = len(set(modified_files) & set(test_covered_files)) / len(modified_files) if modified_files else 0 # 2. 历史缺陷特征 # 获取被修改文件在过去90天的缺陷数 ninety_days_ago = datetime.now() - timedelta(days=90) bug_count = 0 for file in modified_files: bug_count += get_bug_count_for_file(file, since=ninety_days_ago) features['modified_files_bug_density'] = bug_count / len(modified_files) if modified_files else 0 # 3. 测试用例自身特征 test_history = get_test_execution_history(test_case_id, limit=10) features['recent_failure_rate'] = sum(1 for run in test_history if run['status'] == 'FAILED') / len(test_history) if test_history else 0 features['avg_execution_time'] = sum(run['duration'] for run in test_history) / len(test_history) if test_history else 0 # 4. 开发上下文特征 author = commit.author features['author_avg_bug_intro_rate'] = get_author_bug_intro_rate(author.email) # 该开发历史引入Bug的平均比率 return features # 注意:get_covered_files_by_test, get_bug_count_for_file 等需要根据实际基础设施实现

3.2 第二步:模型训练与更新

我们使用历史数据(代码提交、当时运行的测试用例及其执行结果)来训练KART-RERANK模型。标签就是测试用例是否在该次提交后执行失败(即发现了Bug)。

# 示例:使用LightGBM Ranker进行训练(KART-RERANK的一种实现方式) import lightgbm as lgb import pandas as pd from sklearn.model_selection import train_test_split def train_rerank_model(training_data_path): """ 训练排序模型。 training_data_path: CSV文件,每行是一次提交-测试用例对的特征和标签(1表示失败,0表示通过)。 数据中需要包含一个 'query_id' 列,标识属于同一次提交的所有测试用例(即同一个待排序列表)。 """ df = pd.read_csv(training_data_path) # 准备LightGBM Ranker需要的数据格式 query_groups = df.groupby('query_id').size().to_numpy() # 每次提交有多少个测试用例 X = df.drop(['query_id', 'label'], axis=1).values y = df['label'].values X_train, X_val, y_train, y_val, groups_train, groups_val = train_test_split( X, y, query_groups, test_size=0.2, random_state=42 ) # 创建Ranker数据集 lgb_train = lgb.Dataset(X_train, y_train, group=groups_train) lgb_eval = lgb.Dataset(X_val, y_val, group=groups_val, reference=lgb_train) # 设置参数,使用LambdaRank排序目标 params = { 'objective': 'lambdarank', 'metric': 'ndcg', # 使用NDCG评估排序质量 'boosting_type': 'gbdt', 'num_leaves': 31, 'learning_rate': 0.05, 'feature_fraction': 0.9, 'verbosity': -1, 'seed': 42, } gbm = lgb.train(params, lgb_train, num_boost_round=1000, valid_sets=[lgb_train, lgb_eval], callbacks=[lgb.early_stopping(50), lgb.log_evaluation(50)]) gbm.save_model('test_case_reranker_model.txt') return gbm

模型不需要每天训练,可以每周或每两周用最新的数据重新训练一次,以捕捉项目和团队动态的变化。

3.3 第三步:集成到CI/CD流程

训练好的模型,要能够在线使用。我们在CI流水线中增加了一个“智能测试选择”的步骤。

# 示例:在CI脚本中调用模型进行排序 import joblib import pandas as pd def prioritize_tests_for_commit(commit_hash, candidate_test_cases): """ 对一次代码提交的候选测试用例进行优先级排序。 commit_hash: 本次提交的哈希值 candidate_test_cases: 粗排阶段筛选出的测试用例ID列表 """ # 1. 为每个候选测试用例提取特征 feature_list = [] for test_id in candidate_test_cases: feats = extract_features_for_test(test_id, commit_hash) feature_list.append(feats) feature_df = pd.DataFrame(feature_list) # 2. 加载预训练好的模型 # 假设我们使用joblib保存了模型管道(包含特征处理) model_pipeline = joblib.load('test_rerank_pipeline.pkl') # 3. 预测每个测试用例的“失败概率”得分 # 注意:模型输出的是排序得分,越高表示优先级越高(越可能失败) scores = model_pipeline.predict(feature_df) # 4. 将测试用例ID和得分组合,按得分降序排序 prioritized = sorted(zip(candidate_test_cases, scores), key=lambda x: x[1], reverse=True) prioritized_test_ids = [item[0] for item in prioritized] return prioritized_test_ids # 在CI脚本中 commit_hash = os.environ['CI_COMMIT_SHA'] # 假设get_related_tests函数实现粗排,获取相关测试用例 candidate_tests = get_related_tests(commit_hash) top_k_tests = 100 # 假设本次只允许运行100个测试 tests_to_run = prioritize_tests_for_commit(commit_hash, candidate_tests)[:top_k_tests] # 接下来,触发执行 tests_to_run 中的测试用例

4. 效果怎么样?我们看到了这些变化

这套系统上线运行了几个月,虽然还不能说完美,但确实给测试流程带来了不少积极的变化。

最直观的感受是测试反馈速度变快了。以前,为了确保质量,我们会在代码合并前运行一个中型的“门禁测试套件”,大约500个用例,需要跑40分钟。现在,我们让模型从这500个用例中选出它认为最重要的100个先跑。这100个测试的完成时间缩短到了10分钟以内。开发者在提交代码后,能更快地得到第一轮质量反馈。如果这100个高优先级测试都通过了,我们心里会踏实很多;如果失败了,也能立刻定位到高风险问题。

缺陷逃逸率有所降低。我们对比了引入智能排序前后三个月的数据,发现发布到生产环境后由客户发现的严重缺陷数量平均下降了约15%。这说明模型在识别“高风险变更”和“脆弱测试”方面是有效的,优先执行的测试确实抓住了更多关键问题。

当然,也有挑战。比如,特征工程是持续的过程。一开始我们只用了代码变更和测试历史失败率,效果一般。后来加入了模块缺陷密度、开发者历史数据后,排序效果才有了明显提升。模型也需要定期用新数据重新训练,否则会“过时”。

5. 总结与展望

回过头看,将KART-RERANK这类重排序模型引入测试优先级排序,本质上是用数据驱动的方法,替代了原本依赖经验或简单规则的策略。它不要求测试人员去精确预判哪段代码会出问题,而是让模型从历史数据中学习复杂的模式和关联。

实际用下来,它更像一个“测试辅助决策系统”,而不是完全取代人类。它帮我们解决了在资源紧张时“先测什么”的决策难题,让有限的测试资源能更精准地投入到风险最高的地方。对于追求高效和质量的工程团队来说,这无疑是一个值得尝试的方向。

未来,我们还想探索更多。比如,能否把代码变更的语义信息(通过代码嵌入技术)也作为特征?能否实现更细粒度的“测试用例片段”排序,而不是整个用例?模型能否根据实时测试结果动态调整后续的排序?这些都是有趣且具有实用价值的问题。

技术总是在解决一个又一个的实际问题中前进的。如果你也在为测试效率发愁,不妨从收集数据、构建最简单的特征开始,试试看机器学习能带来什么改变。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

http://www.cnnetsun.cn/news/1357525.html

相关文章:

  • FreeRTOS命令行进阶:如何用CLI组件实现动态参数计算(含sum命令踩坑记录)
  • 从自行车模型到轨迹跟踪:纯追踪算法的核心推导与实践调优
  • 一篇文章掌握OBS多平台直播:obs-multi-rtmp插件终极指南
  • RT-detr训练避坑指南:如何安全绕过Image size限制与decompression bomb报错
  • [PYQT] VScode 集成 Qt Designer:从零构建带资源管理的桌面应用模板
  • 从数据到洞察:Python lifelines库Kaplan-Meier Fitter实战指南
  • Deepin系统SSH服务配置与Cpolar内网穿透实现高效远程办公
  • AI读脸术高可用部署:手把手教你实现服务自动恢复机制
  • 别再手动截图了!用Apache PDFBox 2.0.27 + Maven,5行Java代码搞定PDF批量转高清PNG
  • Android相机权限被禁用?手把手教你解决CAMERA_DISABLED (1)错误
  • Qwen1.5-1.8B-Chat-GPTQ-Int4实战手册:支持流式输出、历史上下文、角色设定
  • Python入门到实战:手把手教你调用DAMOYOLO-S完成目标检测
  • VASP6.4.2安装vtstcode-199避坑指南:为什么make顺序错了会失败?
  • lychee-rerank-mm环境配置:Ubuntu 22.04 + CUDA 12.1 + PyTorch 2.3适配清单
  • OpenClaw技能生态实战:用ollama-QwQ-32B自动生成周报并邮件发送
  • 快速构建Multisim 14.0安装引导原型:用快马AI十分钟打造可视化教程助手
  • WorkshopDL终极方案:跨平台游戏模组下载的高效实践
  • Llama Factory效果展示:微调前后对比,AI对话质量显著提升案例
  • 霜儿-汉服-造相Z-Turbo与Claude Code对比:不同AI模型在创意编程中的角色
  • 如何在OBS中为音频源添加VST插件:一个技术实现视角
  • Qwen3智能字幕对齐教程:清音刻墨错误对齐定位与人工修正快捷键大全
  • Linux下Matplotlib中文乱码终极解决方案:从字体安装到全局配置(附SimHei.ttf下载)
  • 美胸-年美-造相Z-Turbo:不止是快,实测主体一致性、细节丰富度大幅提升
  • R语言矩阵操作避坑指南:如何快速定位和解决‘subscript out of bounds‘错误
  • 基于SiameseAOE的Java面试题智能解析与观点抽取应用
  • Jupyter Notebook虚拟环境缺失?三步快速配置ipykernel的实战指南
  • 【目标跟踪】Anti-UAV数据集:多模态挑战与评估标准深度解析
  • Microsoft Teams与Outlook邮件组联动:5分钟搞定团队创建与成员同步
  • Docker容器中文乱码终极解决方案:Ubuntu镜像下5步搞定(附字体包)
  • 生态模型避坑指南:七鳃鳗性别比例建模中的常见错误与解决方案