Robot Framework 7.1 RC2 发布详解:Listener 与 VAR 语法增强实战指南

原创2026-09-23 12:58:07599 阅读
文章标签:测试RPA接口测试

Robot Framework 7.1 RC2 发布详解:Listener 与 VAR 语法增强实战指南

Robot Framework 7.1 是继 7.0 之后的功能版本,重点增强了 Listener 监听器接口与 VAR 变量语法。本文基于官方发布说明 rf-7.1rc2.rst,结合仓库源码深度解析 7.1 RC2 的全部新特性、向后不兼容变更与修复清单,帮助你在升级前充分评估影响、升级后快速上手新 API。

版本概览与安装方式

Robot Framework 7.1 RC2 发布于 2024 年 9 月 3 日(星期二),是 7.1 的第二个发布候选版本,包含所有计划中的功能与变更。相对于第一个 RC(rf-7.1rc1),本版本主要变更集中在:

  • 控制台结果文件路径输出为超链接(issue [#5189])
  • 允许 Listener 修改 WHILE 循环限制(issue [#5194])

官方邀请社区成员在各自环境中充分测试,以便在 9 月 9 日(星期一)正式版发布前修复可能的回归问题。如发现问题,可通过 #devel 频道反馈到 Robot Framework Slack,或在 issue tracker 提交缺陷。

安装命令

已安装 pip 的情况下,安装最新可用版本:

pip install --pre --upgrade robotframework

或精确安装此版本:

pip install robotframework==7.1rc2

也可以从 PyPI 下载包后手动安装。更完整的安装方式参见 INSTALL.rst。

最重要的增强:Listener 接口

Listener 接口在 Robot Framework 7.0 中被大幅增强,7.1 在此基础上又增加了四项重要能力。

1. 用 ROBOT_LISTENER_PRIORITY 控制监听器调用顺序

监听器现在可以通过 ROBOT_LISTENER_PRIORITY 属性控制调用顺序(issue [#3473])。

从源码实现看,优先级解析发生在 Listener 门面(Facade)初始化阶段。在 src/robot/output/listeners.py 中:

self.priority = self._get_priority(listener)

def _get_priority(self, listener):
    priority = getattr(listener, 'ROBOT_LISTENER_PRIORITY', 0)
    try:
        return float(priority)
    except (ValueError, TypeError):
        raise DataError(f"Invalid listener priority '{priority}'.")

要点:

  • 未设置该属性时默认优先级为 0;
  • 优先级会被转换为浮点数,数值越小越先被调用;
  • 若设置为非法值(无法转为 float),会抛出 DataError,并提示 Invalid listener priority。

示例(监听器类中声明):

class MyListener:
    ROBOT_LISTENER_PRIORITY = -10  # 比其他默认监听器更早执行

    def start_suite(self, data, result):
        print("early suite start")

2. 监听器可以改变执行状态

监听器现在可以修改执行状态(issue [#5090])。例如,将关键字状态从 PASS 改为 FAIL:

  • 旧行为:只影响该关键字本身,执行继续;
  • 新行为:执行停止,当前测试或任务被标记为失败。

这使得监听器能够实现更精细的执行控制,例如在特定条件下强制让用例失败并终止后续步骤。

3. Listener API 版本 3 补齐导入相关方法

Listener API 版本 3 新增了库、资源文件和变量文件导入相关方法(issue [#5008]),至此 V3 拥有与 V2 完全一致的方法集。

从 src/robot/output/listeners.py 可以看出 V3 门面采用了「回退」机制——例如 start_keyword 会回退到 start_body_item,WHILE 相关方法也会回退到 body item 方法:

class ListenerV3Facade(ListenerFacade):
    def __init__(self, listener, name, log_level, library=None):
        ...
        start_body_item = get('start_body_item')
        end_body_item = get('end_body_item')
        self.start_keyword = get('start_keyword', start_body_item)
        self.end_keyword = get('end_keyword', end_body_item)
        # WHILE
        self.start_while = get('start_while', start_body_item)
        self.end_while = get('end_while', end_body_item)
        self.start_while_iteration = get('start_while_iteration', start_body_item)
        self.end_while_iteration = get('end_while_iteration', end_body_item)

注意:V3 门面同时支持蛇形命名(start_suite)与驼峰命名(startSuite)两种方法名,见 _get_method_names 实现。

4. 监听器可修改 WHILE 循环限制

监听器现在可以修改 WHILE 循环的限制值(issue [#5194],由社区贡献者 Adrian Błasiak 实现)。在 V3 监听器的 start_while 中修改 result.limit 即可影响循环的执行次数。

VAR 语法增强

VAR 语法在 7.0 中引入,用于以统一语法在不同作用域创建变量,7.1 对其进行了两处关键增强。

1. 创建变量时记录变量值

VAR 创建的变量值现在会被记录到日志,与 Set Test Variable、Set Suite Variable 等关键字的行为一致(issue [#5077])。

从 src/robot/running/model.py 的 Var.run 实现可以看到:

def run(self, result, context, run=True, templated=False):
    result = result.body.create_var(self.name, self.value, self.scope, self.separator)
    with StatusReporter(self, result, context, run):
        if self.error and run:
            raise DataError(self.error, syntax=True)
        if not run or context.dry_run:
            return
        scope, config = self._get_scope(context.variables)
        set_variable = getattr(context.variables, f'set_{scope}')
        try:
            name, value = self._resolve_name_and_value(context.variables)
            set_variable(name, value, **config)
            context.info(format_assign_message(name, value))
        except DataError as err:
            raise VariableError(f"Setting variable '{self.name}' failed: {err}")

其中 format_assign_message(name, value) 正是生成日志消息的关键调用。

安全注意(向后不兼容):由于变量值会被记录,可能泄露机密信息。若担心这一点,可用 --max-assign-length 命令行选项禁用/限制所有变量赋值的日志输出。

2. 新增 SUITES 作用域

新增 SUITES 作用域,用于将变量设置到当前套件及其所有子套件(issue [#5060])。此前 SUITE 作用域只影响当前套件而不影响其子套件。此增强使 VAR 语法在功能上与 Set Suite Variable 关键字兼容(后者以略有不同的语法支持相同功能)。

源码中作用域解析逻辑位于 src/robot/running/model.py:

def _get_scope(self, variables):
    if not self.scope:
        return 'local', {}
    try:
        scope = variables.replace_string(self.scope)
        if scope.upper() == 'TASK':
            return 'test', {}
        if scope.upper() == 'SUITES':
            return 'suite', {'children': True}
        if scope.upper() in ('LOCAL', 'TEST', 'SUITE', 'GLOBAL'):
            return scope.lower(), {}
        raise DataError(...)

SUITES 被映射为 set_suite(..., children=True),即向当前及所有子套件设置变量。语法层面的合法取值定义在 src/robot/parsing/model/statements.py:

class Var(Statement):
    type = Token.VAR
    options = {
        'scope': ('LOCAL', 'TEST', 'TASK', 'SUITE', 'SUITES', 'GLOBAL'),
        'separator': None
    }

VAR 的完整合法作用域为:LOCAL、TEST、TASK、SUITE、SUITES、GLOBAL。

使用示例:

*** Test Cases ***
Example
    VAR    ${name}    value    scope=SUITES
    # 当前套件及其全部子套件均可见 ${name}

其他增强

控制台超链接

执行完成后写入控制台的日志与报告路径现在是超链接,便于直接在浏览器中打开(issue [#5189])。这要求终端支持超链接:

  • 几乎所有 Linux 和 macOS 终端均支持;
  • 经典的 Windows Console 不支持,但较新的 Windows Terminal 以及 Windows 上大多数第三方终端兼容。

底层实现采用终端 OSC 8 超链接语法,见 src/robot/output/console/highlighting.py:

def link(self, path):
    if not self._links:
        return path
    try:
        uri = path.as_uri()
    except ValueError:
        return path
    # Terminal hyperlink syntax is documented here:
    # https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
    return f'\033]8;;{uri}\033\\{path}\033]8;;\033\\'

控制台链接行为可通过命令行选项控制,robot 与 rebot 均支持:

--consolelinks auto|off   Control making paths to results files hyperlinks.

该选项在 src/robot/run.py 与 src/robot/rebot.py 中均有声明。

命名参数的程序化 API

7.1 引入了以编程方式使用命名参数的新 API(issue [#5143]),面向在测试执行前或执行中修改测试/任务的 pre-run modifiers 与 listeners。7.0 曾尝试添加类似 API(issue [#5000]),但因引发向后不兼容问题而在 7.1 中回退(issue [#5031]),新 API 希望规避这些问题。

从源码看,该 API 以类型别名与运行模型字段的形式落地。在 src/robot/api/interfaces.py 中:

NamedArgs = Mapping[str, Any]

运行模型中的 Keyword 支持 named_args 字段,src/robot/running/model.py:

"""When creating keywords programmatically, it is possible to set :attr:`named_args`"""
__slots__ = ['named_args', 'lineno']
...
def __init__(self, ..., named_args: 'Mapping[str, Any]|None' = None, ...):
    self.named_args = named_args
...
if self.named_args is not None:
    data['named_args'] = self.named_args

同时关键字运行器在解析参数时会合并命名参数(如 src/robot/running/librarykeywordrunner.py):

if data.named_args:
    args += tuple(f'{n}={v}' for n, v in data.named_args.items())

翻译与兼容性更新

  • 新增韩语翻译(issue [#5187],由 Hyeonho Kang 贡献);
  • 更新荷兰语翻译(issue [#5148],由 J. Foederer 贡献),部分旧术语不再生效;
  • 官方兼容 Python 3.13(issue [#5091])。官方声明无需修改代码,因此较旧版本的 Robot Framework 也应能正常工作。

向后不兼容变更

升级到 7.1 前请特别关注以下三点:

  1. 变量值日志可能泄露机密信息(issue [#5077]):VAR 语法现在会记录变量值。若担心泄露,用 --max-assign-length 禁用或限制变量赋值日志。

  2. 荷兰语翻译更新(issue [#5148]):部分旧术语不再生效。如有问题,可创建包含旧变体的自定义语言文件;若影响面较大,官方也可能考虑调整本地化系统,让旧术语仍然可用但产生弃用警告。

  3. BDD 前缀行为变更(issue [#4577]):若关键字名形如 ${kind} example,并以 Given good example 方式使用,变量 ${kind} 现在只包含 good,而以前包含 Given good。这通常是一种良性增强,但依赖此前包含前缀的既有代码可能需要更新。

实现上,该变更由 J. Foederer 贡献——当关键字以嵌入参数开头时,不再把 BDD 前缀计入参数值。

完整修复与增强列表(共 25 个 issue)

下表完整列出 7.1 RC2 里程碑中的全部 25 个 issue,按优先级排序:

ID 类型 优先级 摘要 加入版本
#3473 enhancement critical 用 ROBOT_LISTENER_PRIORITY 属性控制监听器调用顺序 rc 1
#5090 enhancement critical 允许监听器改变执行状态 rc 1
#5091 enhancement critical Python 3.13 兼容 rc 1
#5094 bug high 关键字接受 **named 时,含 = 的位置限定参数被误认为命名参数 rc 1
#5181 bug high 含可变值的变量在部分场景下解析错误 rc 1
#5008 enhancement high 为 listener 版本 3 增加库、资源文件与变量文件导入相关方法 rc 1
#5060 enhancement high VAR 语法支持 scope=SUITES 为子套件设置值 rc 1
#5077 enhancement high VAR 语法不像 Set * Variable 那样记录变量值 rc 1
#5143 enhancement high 以编程方式使用命名参数的新 API rc 1
#5187 enhancement high 韩语翻译 rc 1
#5189 enhancement high 终端中结果文件路径显示为超链接 rc 1
#5010 bug medium 设置 PYTHONWARNDEFAULTENCODING 产生警告 rc 1
#5151 bug medium Evaluate 关键字未考虑添加到 builtins 模块的属性 rc 1
#5159 bug medium 使用 Rebot 处理不存在的 JSON 输出文件时错误信息不佳 rc 1
#5177 bug medium 舍入错误导致状态色条显示异常 rc 1
#3418 enhancement medium Import Resource 应在 dry-run 中执行 rc 1
#4577 enhancement medium 若 BDD 关键字以嵌入参数开头,从参数值中剥离前缀 rc 1
#4821 enhancement medium Format String:允许使用含 = 的模板字符串而无需转义 rc 1
#5038 enhancement medium Dialogs:Get Selection From User 支持默认选项 rc 1
#5054 enhancement medium Should Contain 更好地支持 bytes rc 1
#5087 enhancement medium 将 output.xml 的生成时间添加到 Result 对象 rc 1
#5135 enhancement medium 支持含 week 值的时间字符串 rc 1
#5148 enhancement medium 更新荷兰语翻译 rc 1
#5194 enhancement medium 允许在 listener V3 中修改 WHILE 限制 rc 2
#5169 bug low 匹配含嵌入参数的关键字时空格未规范化 rc 1

其中 #5194(WHILE 限制修改)是第二个 RC 新增的条目,其余均在第一版 RC 中已包含。

与 7.1 RC1 的差异

相比第一个发布候选(详见 rf-7.1rc1.rst),RC2 的变更集中在两处:

  1. 控制台超链接(#5189):结果文件路径在支持超链接的终端中可点击;
  2. WHILE 循环限制可由监听器修改(#5194):在 V3 监听器的 start_while 钩子中调整 result.limit 即可生效。

致谢与后续行动

Robot Framework 开发由 Robot Framework Foundation 及其 60+ 成员组织赞助。本版本亦获得多位社区成员的贡献:

  • J. Foederer:增强嵌入参数语法(#4577),更新荷兰语翻译(#5148);
  • Hyeonho Kang:韩语翻译(#5187);
  • Adrian Błasiak:监听器修改 WHILE 循环限制(#5194);
  • @ChristopherJHart:时间字符串支持 week(#5135);
  • @wendi616:Import Resource 在 dry-run 中执行(#3418);
  • Peter:Get Selection From User 默认值支持(#5038);
  • Tatu Aalto:从 output.xml 提取生成时间到 Result 对象(#5087);
  • @droeland:Should Contain 对 bytes 的支持(#5054)。

如果你在测试 7.1 RC2 时发现回归,请在正式版(原定 2024 年 9 月 9 日发布)前通过 issue tracker 反馈,以帮助官方在最终版本中修复问题。相关的自动化测试用例可在 atest 与 utest 目录中查阅,源码实现集中在 src/robot 下的 output、running、parsing 等模块。

登录后查看全文
robotframework