2026 年 6 月,SmartBear 在 TestComplete 中正式启用 Vision AI(官方称 visual object detection)。官方将其描述为"首个把属性识别、OCR 与视觉 AI 统一的平台"——这是厂商表述,不是第三方结论。本文只依据官方文档与实际脚本行为,讲清它能做什么、现在还做不到什么。

一、先搞懂它站在哪一层

很多人的第一个误解,是以为视觉 AI 来了就可以抛弃属性识别。恰恰相反。

TestComplete 的对象识别是分层的:

  1. 属性识别——读控件暴露出来的属性(UIA、DOM、MSAA 等)。属性齐全且稳定时,这是首选,最快也最稳。
  2. OCR——把界面当图片,读里面的文字。
  3. 视觉识别(Vision AI)——把界面当图片,用视觉模型判断"这是个按钮"“那是个输入框”。

官方文档的定位很明确:视觉识别是对属性识别的补充,可在属性识别碰壁时作为自动兜底(automatic failover)。属性还在的时候刻意用视觉识别,是拿快而稳的路换慢而软的路。

真正必须动用第三层的,是下面这四类界面:

  • canvas 自绘界面:交易终端、BI 仪表盘、地图类应用,内容直接画成像素,DOM 与可访问属性一概没有
  • 自定义图形引擎:CAD、医学影像、仿真类软件,用私有渲染,不暴露标准属性
  • 遗留桌面程序:早于现代可访问性标准建成,业务上又不能重写
  • 虚拟桌面(Citrix / 远程桌面):整屏以图像流呈现,自动化工具看不到任何独立控件

它们的共同点是:不是定位难,是根本没有可定位的东西。

二、开工前:四个前置条件,漏一个就白忙

  1. 许可:需 Pro Bundle,或单独购买 Intelligent Quality (IQ) add-on
  2. 扩展File → Install Extensions → Intelligent Quality,勾选 Visual Object Detection,完成后重启 TestComplete
  3. 网络:开启后,被测应用截图与 UI 元数据会发往 SmartBear 托管的 AI 服务,需放通端点 https://ocr-service.prod.testcomplete.com内网、涉密或有数据出境限制的环境,务必提前与 IT 和合规部门确认,否则功能等于不可用
  4. 进程优先级项目 → Properties → Visual Object Detection,添加要启用视觉识别的进程名;填 * 表示对所有进程生效。未列入的进程仍走标准识别顺序

三、实战一:VOD 录制出来的代码长什么样

开启后正常录制,交互时 TestComplete 会把截图送去做视觉检测,返回的元素目录进入 Object Browser,脚本里通过 VODWindow 访问。官方录制产物大致如下:

// 录制 Vision AI 操作后自动生成的脚本(官方示例)
function Test1() {
  Sys.Process("xtop").VODWindow("HCS16139P", "*").Click(1058, 215);
  Sys.Process("xtop").VODWindow("HCS16139M").BOTTOM.Click();
  Sys.Process("xtop").VODWindow("HCS16139P", "*").Click(1057, 223);
  Sys.Process("xtop").VODWindow("HCS16139M").TOP.Click();
  Sys.Process("xtop").VODWindow("HCS16139M").StandardOrientation.Click();
}

注意第一、三行的 Click(1058, 215)——这是录制时刻的绝对坐标。窗口位置、分辨率、DPI 缩放一变,这两行最先崩。

改进办法:用控件自身尺寸算中心点,而不是复刻坐标。

/**
 * 按控件路径定位 VOD 元素,并以中心点点击,规避录制坐标漂移。
 * @param {string} processName 目标进程名,如 "xtop"
 * @param {string} windowId    VOD 窗口标识
 * @param {string} controlPath 子控件路径,多级用 "." 分隔,无子控件传 ""
 * @param {number} timeout     等待毫秒数
 * @returns {boolean} 是否点击成功
 */
function clickVodControl(processName, windowId, controlPath, timeout) {
  var win = Sys.Process(processName).VODWindow(windowId, "*");
  if (!win.Exists) {
    Log.Error("VOD 窗口未找到", "process=" + processName + ", windowId=" + windowId);
    return false;
  }

  var ctrl = win;
  if (controlPath !== "") {
    var parts = controlPath.split(".");
    for (var i = 0; i < parts.length; i++) {
      ctrl = ctrl.WaitChild(parts[i], timeout || 10000);
      if (!ctrl.Exists) {
        Log.Error("VOD 子控件未找到",
                  "路径=" + controlPath + ",在 \"" + parts[i] + "\" 处中断");
        return false;
      }
    }
  }

  // 用控件自身尺寸计算中心点,比照搬录制坐标稳得多
  ctrl.Click(Math.round(ctrl.Width / 2), Math.round(ctrl.Height / 2));
  Log.Message("已点击 VOD 控件: " + (controlPath === "" ? windowId : controlPath));
  return true;
}

// 调用
clickVodControl("xtop", "HCS16139M", "StandardOrientation", 10000);

WaitChild 是 TestComplete 通用的等待子对象方法,在 VOD 返回的对象上同样可用;若你的版本在该对象上不支持,直接以属性方式访问(如 .BOTTOM)亦可。

四、实战二:三种识别怎么串起来

真实项目几乎不会只用一种识别方式。下面场景很典型:Citrix 里跑着终端,外层是普通可识别窗口,中间行情区是 canvas 自绘,数值还画在图里。

function MixedRecognitionFlow() {
  // —— 第一层:属性识别。外层窗口属性完整,走 Name Mapping 别名,最快最稳
  var shell = Aliases.citrixShell;
  shell.Activate();

  // —— 第二层:视觉识别。canvas 自绘的工具栏,属性层拿不到,交给 VOD
  if (!clickVodControl("xtop", "HCS16139M", "Refresh", 10000)) {
    return false;
  }

  // 等待行情区完成重绘,视觉识别阶段务必留足渲染时间
  var canvasHost = Aliases.citrixShell.QuotePanel;
  if (!canvasHost.WaitProperty("Enabled", true, 15000)) {
    Log.Warning("行情区在 15 秒内未完成重绘,后续断言可能不稳定");
  }

  // —— 第三层:OCR。数值是画在图上的,只能读图取字
  var quoteArea = canvasHost.Picture(120, 60, 420, 260);   // x, y, width, height
  var doc = OCR.Recognize(quoteArea);

  Log.Message("行情区 OCR 结果", doc.FullText);
  return aqString.Find(doc.FullText, "最新价", 0, false) > -1;
}

三段各司其职:能拿属性的绝不浪费视觉识别,拿不到属性的才降级,需要读图里的字就交给 OCR。这也是官方推荐的混合思路。

五、首版没有检查点,断言怎么办

官方文档写明:当前版本 Vision AI 不支持 checkpoints、operations 与 Object Spy,仅支持在测试录制阶段捕获对象。视觉识别现在主要负责"找到并操作",断言这一环要自己补。有两条可行路径。

文本断言:弃用 CheckText,改用 FullText

CheckText 只在日志里丢一个通过或失败,排查时拿不到上下文。改用 FullText 自行比对,失败时能留下 OCR 实际读到的内容:

/**
 * 在指定图像区域中断言文本存在,失败时输出完整 OCR 结果与区域截图。
 */
function assertTextInPicture(picture, expected, caseSensitive) {
  var text = OCR.Recognize(picture).FullText;
  var hit = aqString.Find(text, expected, 0, caseSensitive === true) > -1;

  if (hit) {
    Log.Message("命中预期文本", "期望=" + expected);
  } else {
    Log.Error("未找到预期文本",
              "期望=" + expected + "\r\nOCR 实际识别结果:\r\n" + text);
    Log.Picture(picture, "断言区域截图");   // 把现场一并存档,便于复盘
  }
  return hit;
}

视觉断言:像素比对 + 差异图落盘

对图表、仪表盘这类"没法用文字描述正确性"的对象,用基线图片做像素级回归,并把差异图存下来:

/**
 * 与基线图片做像素比对,失败时生成差异图并落盘。
 * 用于替代首版缺失的 VOD 检查点。
 */
function assertVisualBaseline(obj, region, baselineName, pixelTolerance) {
  var actual = (region === null)
    ? obj.Picture()
    : obj.Picture(region[0], region[1], region[2], region[3]);

  // Regions.Compare(图1, 图2, 透明, 含鼠标, 报差异, 容差, 消息类型)
  var ok = Regions.Compare(baselineName, actual, false, false, true,
                           pixelTolerance || 0, lmError);

  if (!ok) {
    var baseline = Regions.GetPicture(baselineName);
    var diff = baseline.Difference(actual);
    if (diff !== null) {
      var stamp = aqConvert.DateTimeToFormatStr(aqDateTime.Now(), "%Y%m%d_%H%M%S");
      var outFile = "D:\\QA\\Diff\\" + baselineName + "_" + stamp + ".png";
      diff.SaveToFile(outFile);
      Log.Error("视觉基线比对失败", "差异图已保存至: " + outFile);
    }
  }
  return ok;
}

// 调用:对 Citrix 中的图表区域做视觉回归,容忍 50 个像素的差异
assertVisualBaseline(Aliases.citrixShell.ChartPanel, [40, 30, 800, 420],
                     "Baseline_Chart", 50);

容差建议留余量:字体渲染、抗锯齿、远程桌面压缩都会带来几个像素的差异,设 0 容易被噪声反复误伤。

六、跑进 CI:命令行与退出码

GUI 测试上 CI 的两个坑:一是需要交互式用户会话(Session 0 隔离下服务账户无法模拟键鼠),二是退出码处理。

@ECHO OFF
SET TE="C:\Program Files (x86)\SmartBear\TestExecute 15\Bin\TestExecute.exe"
SET PROJ="D:\QA\TradingClient\TradingClient.pjs"
SET OUT=D:\QA\Reports\%BUILD_NUMBER%

%TE% %PROJ% /run /SilentMode /ForceConversion /ns /exit ^
  /project:CitrixRegression ^
  /ExportLog:%OUT%\result.mht ^
  /ExportLog:%OUT%\result.htmlx ^
  /ErrorLog:%OUT%\error.txt ^
  /DoNotShowLog

IF ERRORLEVEL 4  GOTO Timeout
IF ERRORLEVEL 3  GOTO CannotRun
IF ERRORLEVEL 2  GOTO Errors
IF ERRORLEVEL 1  GOTO Warnings
IF ERRORLEVEL 0  GOTO Success

:Timeout     ECHO 执行超时 & EXIT /B 4
:CannotRun   ECHO 无法运行:检查项目、测试项与插件配置 & EXIT /B 3
:Errors      ECHO 测试存在错误 & EXIT /B 2
:Warnings    ECHO 测试通过但有警告 & EXIT /B 1
:Success     ECHO 无错误无警告 & EXIT /B 0

退出码含义:0 无错误无警告,1 有警告无错误,2 有错误,3 无法运行(项目打不开、测试项缺失、插件未启用、脚本语法错误等),4 超时,-1 许可检查失败。

CI agent 建议跑在真实用户会话下而非 SYSTEM 账户;否则即使逻辑全过,也可能因弹窗在静默模式下无法处理而返回 -1

七、清单:它现在还不能做什么

限制说明
不支持检查点首版无 checkpoint,断言需用 OCR 或图片比对自行实现
不支持 Object Spy无法用 Spy 探查视觉识别出的元素
仅录制阶段捕获检出对象发生在测试录制时
需要外网端点需放通 ocr-service.prod.testcomplete.com
许可门槛需 Pro Bundle 或 IQ add-on
不替代属性识别属性可用且稳定时,属性识别仍是首选

至于"视觉识别会不会让脚本永不失效"——不会。它解决的是属性根本不存在的问题,外观大幅改版时同样要重新捕获。当成"多一层兜底"比"免维护"准确得多。

八、结语:下一步可以做什么

视觉 AI 打开的空间不小——那些长期被划进"只能手工测"的区域,第一次有了进入自动化回归体系的可能。对受监管行业还有一层意义:流程一旦可重复执行,产出的就是可留存、可追溯的执行记录,而不是一堆人工截图。

如果被测对象里有这类界面,建议分三步推进:

  1. 盘点场景——把至今只能手工测的界面列出来,判断属于 canvas 自绘、自定义图形引擎、遗留桌面还是虚拟桌面
  2. 确认前置条件——许可形态、扩展是否安装、内网能否放通 AI 服务端点,这三条决定项目能否起步
  3. 小范围 POC——挑一个高频稳定的流程先验证,不要一上来铺全量

如果你正在做类似场景,或卡在许可选型、内网部署这些环节,欢迎评论区留言,把界面类型和控制件情况说清楚,一起判断走哪层识别更合适;涉及报价、POC 环境搭建等问题,也可以站内私信,看到会回复。
在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐