首页 / 资讯中心 / 文章详情

Robot Framework测试自动化入门:关键字驱动框架实战与踩坑记录

Robot Framework测试自动化入门:关键字驱动框架实战与踩坑记录 ★ FEATURED ARTICLE
做测试自动化这几年我见过太多人一上来就抱着pytest写脚本把测试用例活活写成了代码到最后接口变了、页面变了代码改了又改维护成本高得吓人。后来接触了机器人框架也就是Robot Framework这种关键字驱动的框架反而在团队协作和用例可读性上给了我很大的帮助。这篇博客不是教科书是我在实际实施机器人框架测试自动化过程中的经验和踩坑记录。如果你是第一次接触Robot Framework或者已经在用但总感觉不得要领这篇文章能帮你把基础打扎实。它是什么一个开源、通用的自动化测试框架能做什么Web、接口、移动端、数据库等领域的自动化测试都能做适合谁想降低自动化测试门槛、让业务同事也能参与脚本维护的团队。为什么我会说机器人框架比纯pytest脚本更适合某些场景因为它把“操作步骤”和“测试逻辑”彻底分开了。你写的用例是一张表格每一行是一个动作、一个断言哪怕是完全不熟悉代码的测试人员也能一字一句地读出来“打开浏览器输入框内填账号点击登录按钮验证提示文字”。这种可读性是天然带来的不是靠注释和规范硬撑出来的。这篇文章我会从框架选型、环境搭建、项目结构、真实用例、问题排查这几个方面把机器人框架测试自动化的第一课讲透。1. 从Pytest、Selenium到Robot Framework为什么我需要“机器人框架”1.1 Robot Framework的本质关键字驱动很多人第一次听到“机器人框架”都会以为是什么硬件机器人实际上它是一套纯软件层面的自动化测试框架本名Robot Framework。它的核心思想是“关键字驱动”测试用例不再是一个个函数调用而是通过关键字来组织。关键字是什么可以简单理解成一个动作单元比如“打开浏览器”“输入用户名”“点击登录”都可以是一个关键字。这些关键字背后可能是一个Python函数又或者是其他底层库封装出来的能力。这种设计带来的最大好处就是测试用例的抽象层次提高了。你在用例里写的不是driver.find_element(By.ID, username).send_keys(admin)而是Input Text idusername admin。一眼就能看出来这段用例在做什么。机器人框架自带大量内置关键字比如Log、Should Be Equal、Run Keyword If同时还可以通过导入外部库扩展关键字比如SeleniumLibrary、RequestsLibrary、AppiumLibrary。所以它不是一个只能做Web自动化的玩具而是一个能在多个测试领域复用的通用框架。我经常拿它跟pytest做对比。pytest是代码优先的框架断言、fixture、参数化都靠写Python代码实现灵活性极高但学习曲线也高而且代码写多了之后用例的可读性完全取决于写代码的人。Robot Framework则是表格驱动用例本身就像一张需求说明稍微培训一下业务人员也能看懂甚至参与维护。注意我这里不是说Robot Framework比pytest更好而是它有完全不同的使用场景。如果你跟我一样团队里有不少不懂代码的同事或者你要在多个项目间快速复制自动化能力机器人框架会舒服很多。1.2 与Pytest、Selenium、Appium的关系这里必须把概念理清楚因为我在面试里问过的人十个有九个会搞混。Robot Framework和pytest属于同一个层级都是测试框架负责组织和执行测试用例。而Selenium、Appium属于更底层的自动化工具它们负责驱动浏览器、App去做实际操作。机器人框架本身不具备直接驱动浏览器的能力它要靠导入SeleniumLibrary来封装Selenium WebDriver。也就是说Robot Framework SeleniumLibrary才等于“Web自动化测试框架完整体”。同样的接口自动化方面Robot Framework本身没有发HTTP请求的能力需要导入RequestsLibrary而RequestsLibrary底层用的就是Python界大名鼎鼎的Requests库。移动端自动化则需要导入AppiumLibrary它的能力封装自Appium。所以热词里那些selenium自动化测试框架、appium自动化测试、接口自动化测试框架并不是机器人框架的替代品而是它下面的“零件”。理解了这个关系你以后看任何自称“机器人框架自动化”的项目一眼就能看穿它用了什么底层技术。1.3 选型背后的实际考量我选机器人框架的时候想得很清楚不是为了追新而是因为三个实实在在的原因。第一可读性。我们团队有一个业务测试工程师他对Python一窍不通但看我写了两天机器人用例之后居然能自己照葫芦画瓢改测试数据。换成pytest他连def test_login(self)缩进问题都搞不定。第二可扩展性。机器框架自带十几个标准库覆盖文件、字符串、操作系统、日期时间等常见操作不够用还能用Python写自定义关键字库扩展边界跟pytest一样宽。第三报告能力。机器人框架默认就会输出漂亮的HTML报告和日志不需要再额外接Allure或者自己写报告脚本对于需要定期交付报告的团队来说省了很大的事。当然缺点也明显。如果你写的关键字比较多出了问题调试起来没有pytest那么直接毕竟中间隔了一层语法。而且Robot Framework在写复杂循环、复杂字符串处理时那种表格语法会显得很笨拙。所以我现在的工作流是简单场景直接机器人框架复杂数据逻辑用Python自定义库必要时混用pytest跑回调。后面我会细说怎么混。2. 环境准备与第一个机器人测试用例2.1 安装环境从0到能用其实只有三步很多新手卡在环境安装上其实真的不难。我以Windows为例Mac和Linux基本一样。首先确保你已经安装了Python 3.9以上版本并勾选了Add Python to PATH。然后在命令行执行pip install robotframework装完后验证一下robot --version能输出版本号就说明框架本体装好了。接着你还需要根据自己要做的测试类型装扩展库。我通常一次性把常用库装齐pip install robotframework-seleniumlibrary pip install robotframework-requestslibrary pip install robotframework-appiumlibrary这里有个坑SeleniumLibrary的版本需要和底层的selenium版本匹配所以我习惯直接装robotframework-seleniumlibrary它会自动拉取对应的Selenium版本。装完之后用pip show robotframework-seleniumlibrary看版本。如果后面运行用例时报类似“cannot import name xxx”的错大概率是selenium和seleniumlibrary版本冲突这时候可以重新升级或降级。2.2 项目目录结构设计项目一开始就乱后面一定会痛苦。我推荐一个非常经典的结构RobotProject/ ├── tests/ │ ├── web_login.robot │ └── api_login.robot ├── resources/ │ ├── common_keywords.robot │ └── variables.robot ├── results/ └── config/ └── config.pytests放测试套件resources放公共关键字和变量results放输出报告config放环境配置。当你用例多了以后还可以在tests下按模块分子目录。这个结构的核心是分层用例层、资源层、配置层。用例层只写场景步骤资源层放复用关键字配置层管环境变量。这样改一个IP地址不用去几十个用例里翻。如果团队用的是Git管理我建议把results目录加进.gitignore。跑步一次自动化就会生成一堆output.xml、log.html、report.html这些文件体积不小而且每次都会变没必要提交到版本库。评测报告和日志另存到公共路径即可。2.3 第一个用例用内置关键字跑起来我们拿一个不依赖任何外部库的简单用例先把流程走通。在一个.robot文件里分四个区Settings、Variables、Test Cases、Keywords。下面是最小可运行的例子*** Settings *** Documentation 这是一个简单的测试示例 *** Variables *** ${GREETING} Hello Robot Framework *** Test Cases *** 第一个测试用例 Log ${GREETING} Should Be Equal ${GREETING} Hello Robot Framework*** Settings ***里可以导入库、引入资源文件、设置套件级别的参数。*** Variables ***定义变量${GREETING}就是变量。*** Test Cases ***下面写用例。每个用例由若干关键字组成。上面的用例做的事情是记录日志断言变量等于预期字符串。运行方式很简单在这个目录下执行robot tests/demo.robot跑完在results目录下会生成log.html、report.html、output.xml。直接用浏览器打开log.html能看到每一步关键字的执行时间、状态、参数。这是机器人框架最让我满意的地方不用装任何插件天生就有高可读性的测试报告。运行的时候你会在控制台看到类似“1 test, 1 passed”的输出。如果失败还会显示实际值和期望值。从这里就能感受到这种看似简单的关键字组合已经把断言、日志、报告全包了。3. 实操Web自动化与接口自动化的完整落地3.1 用SeleniumLibrary跑通浏览器登录场景在resources里放一个公共资源文件比如common_keywords.robot里面写一些复用关键字*** Settings *** Library SeleniumLibrary *** Keywords *** 打开登录页面 [Arguments] ${url} Open Browser ${url} chrome Maximize Browser Window 输入登录信息 [Arguments] ${username} ${password} Input Text iduser ${username} Input Text idpass ${password} Click Element idlogin_btn这里要注意Open Browser的第二个参数是浏览器类型。chrome需要先下载对应版本的ChromeDriver并且保证chromedriver在PATH里。我每次新弄环境都会忘记这一步其实可以加一行set chromedriver所在的目录加到环境变量PATH中或者直接在Open Browser时指定executable_path参数但我更推荐用自动方式pip install webdriver-manager然后结合它写一个Python自定义库来启动浏览器。这个后面再说。测试用例部分我习惯把测试数据和操作步骤分开。在tests/web_login.robot中这样写*** Settings *** Library SeleniumLibrary Resource ../resources/common_keywords.robot *** Variables *** ${URL} http://example.com/login ${USERNAME} admin ${PASSWORD} 123456 *** Test Cases *** 登录成功校验提示 打开登录页面 ${URL} 输入登录信息 ${USERNAME} ${PASSWORD} Wait Until Page Contains 欢迎回来 [Teardown] Close Browser这里几乎每一行都是大白话。特别是Wait Until Page Contains它自带隐式轮询和超时机制可以避免页面刚加载完元素还没出现的坑。我强烈建议登录类用例至少加一个等待关键字不要登录完直接断言页面渲染不及时的话断言很脆弱。3.2 用RequestsLibrary验证接口自动化接口自动化部分我优先会导入RequestsLibrary。看一个简单例子*** Settings *** Library RequestsLibrary *** Variables *** ${API_URL} http://example.com/api/v1/login *** Test Cases *** 登录接口返回token Create Session login ${API_URL} ${headers} Create Dictionary Content-Typeapplication/json ${payload} Create Dictionary usernameadmin password123456 POST Request login / json${payload} headers${headers}这个用例只是发了一个POST请求但没有断言。所以还需要从响应里拿数据。RequestsLibrary的POST关键字返回的是Response对象可以用${response.status_code}、${response.json()}访问。不过${response.json()}在机器人语法里直接取会有坑我喜欢先Evaluate转成Python对象*** Test Cases *** 登录接口返回token Create Session login ${API_URL} ${resp} POST Request login / json${payload} Should Be Equal As Strings ${resp.status_code} 200 ${body} Evaluate ${resp.json()} requests.Response Should Not Be Empty ${body[token]} token不能为空注意Evaluate的第二个参数告诉机器人框架要计算的Python表达式第三个参数可以传入模块。这里requests.Response其实并不需要传更稳妥的做法是直接${resp.text}再用Evaluate转字典${json} Evaluate json.loads(${resp.text}) json这样写有几个好处一个是避免了机器人框架在解析JSON字符串时的转义问题另一个是可以在json模块下做各种断言。接口自动化最关键的还是要学会从灵活的数据解析中拿到自己想要的字段尤其是嵌套结构。我经常把复杂数据的提取写到自定义关键字里比如“从响应中提取某某字段”和“断言返回结果数量”这样用例会更干净。3.3 报告生成与并行执行机器人框架默认跑完后会在你指定的--outputdir目录生成三个文件。log.html是详细日志按时间轴展示每一步关键字的细节report.html是汇总报告展示通过率、耗时和失败概览output.xml是机器可读的结果可以给CI系统用。命令行里这样指定robot --outputdir results tests/如果用例多跑得慢可以用pabot做并行执行安装命令pip install robotframework-pabot然后pabot --processes 4 --outputdir results tests/它可以同时跑多个套件会自动合并output.xml到report和log。这里有个经验不要把同一个套件内部的用例并行跑因为有些用例会操作同一个浏览器实例并行反而出问题。pabot是按文件分配的所以为了提高并行效率尽量保证套件之间互不依赖。3.4 Appium集成和环境准备移动端自动化方面机器人框架可以通过AppiumLibrary扩展。核心配置是Open Application关键字传入desired capabilities*** Settings *** Library AppiumLibrary *** Test Cases *** 打开商城App首页 Open Application http://localhost:4723/wd/hub ... platformNameAndroid ... deviceNameemulator-5554 ... appPackagecom.shop.app ... appActivity.MainActivity注意Appium版本不同连接URL可能也不同。我实测的坑有两个一是deviceName必须跟adb devices里显示的一致不能随便乱写二是新版的Appium 2.x不再支持remote URL里的/wd/hub后缀需要用http://localhost:4723/差一个路径就会导致连接失败。如果你也遇到“Could not start appium”之类的报错先检查这两点往往比网上到处找其他方法有效。4. 常见问题与排查技巧实录4.1 “Keyword xxx not found” 到底是谁的锅这是机器人框架新手最常遇到的报错。报错信息会明确告诉你找不到哪个关键字。我总结下来背后原因有三类。第一库没有导入。比如你用Open Browser但没有在*** Settings ***里Library SeleniumLibrary那当然找不到了。第二库名或关键字名拼写错了。机器人框架的大小写敏感度有点微妙关键字名不区分大小写但Library名称是区分大小写的。seleniumlibrary和SeleniumLibrary就不一样。第三自定义关键字定义在别的资源文件里但你没有Resource引入。如果真是最后一种我建议在Settings里加上Resource ../resources/xxx.robot相对路径以当前文件所在目录为准很容易搞混更多时候我会用${EXECDIR}变量拼绝对路径。我自己检查的顺序是先看Settings里有没有正确导入再看库有没有装到当前Python解释器环境最后再用robot --help跑一下看是否有语法错误。曾经有一次我在项目里同时开着多个Python环境pip装在了A环境Robot跑在B环境于是怎么都找不到库后来才醒悟过来检查pip列表时务必确保和运行robot命令的是同一个Python环境。4.2 元素定位失败和等待策略Web自动化最气人的就是“明明登录按钮就在那里可脚本就是点不到”。定位失败的原因五花八门最常见的是iframe内嵌。SeleniumLibrary处理iframe时要先Select Frame再操作操作完Unselect Frame不然就找不到里面的元素。另一个是元素被遮挡最常见的是弹窗和动态浮层。这时候用Click Element可能点击无效我有时会改用Click Element At Coordinates但治标不治本。更好的办法是加显式等待Wait Until Element Is Visible或者Wait Until Element Is Enabled等到元素真正可交互了再操作。还有一个容易被忽略的问题元素定位器写得太死。比如iduser这个id前端如果一换版本改成了idusername你的用例就废了。我现在的习惯是在资源文件里把所有定位器抽成变量*** Variables *** ${LOGIN_USER_INPUT} iduser ${LOGIN_PASS_INPUT} idpass ${LOGIN_BTN} xpath//button[typesubmit]修改的时候只要改这一处测试套件几乎不用动。页面结构经常变的项目这种集中管理定位器的方式能省下大量时间。4.3 测试数据清理与状态隔离自动化用例最怕相互污染。假如一个用例注册了用户“test01”另一个用例预期这个用户不存在结果先跑了注册用例后面就失败了。所以我给团队的规矩非常简单每个用例必须有Test Setup和Test Teardown在Setup里创建独立数据在Teardown里清理这些数据。机器人框架的Teardown可以是关键字也可以直接调用Python脚本。举个例子*** Test Cases *** 注册新用户 [Setup] 准备测试数据 ... [Teardown] 清理测试数据 *** Keywords *** 准备测试数据 Create Session api ${API_URL} # 在数据库里插入一条记录 清理测试数据 # 删除这条记录这里注意Teardown即使用例失败也会执行所以清理逻辑一定要写不能偷懒。我曾经见过很多人图省事不写Teardown最后被脏数据折磨得腰酸背痛。另外并行执行时尤其要注意数据库唯一索引。如果两个并行任务同时插入同一用户名就会有一个失败。我用过一个小技巧在数据末尾加随机后缀变量格式为user_${TEST_RUN_ID}然后在Setup里生成随机数。机器人框架自带Generate Random String关键字可以生成随机串拼到数据后面这样并行也就互不干扰了。4.4 调试技巧别只盯着log.html机器人框架提供了比较高效的调试方法。小问题可以直接在用例里加Log Many一口气打印多个变量大问题我会在运行命令时加上--loglevel DEBUG这样在执行日志里能看到关键字底层调用的更多细节。如果开启DEBUG还不够还有一个杀手锏安装robotframework-debuglibrary然后在用例里加一个Debug关键字跑到那里就会开启交互式调试终端你可以直接输入Python表达式或者关键字名看看当前环境里到底是什么状态。这个库帮我解决过好几次棘手问题强烈推荐。不过我自己最常用的调试工具反而是把results/output.xml用文本编辑器打开。它对格式友好每个关键字调用都记录了起止时间和参数。如果某个用例在一台机器上过、一台机器上挂直接对比两个output.xml往往是环境差异而不是用例逻辑问题。4.5 常见问题速查表现象可能原因排查思路运行用例提示“No tests”测试套件里没有写*** Test Cases ***检查.robot文件是否真的有用例页面打开后找不到元素iframe未切换或等待不足先定位iframe或加Wait关键字Open Browser报错Driver not foundchromedriver不在PATH或版本不匹配下载对应版本的chromedriver并设置PATHPOST请求返回403/500没有加token或请求头不对用Log显示请求、响应内容再对照接口文档用例跑得特别慢等待默认超时太长用Set Selenium Timeout调短按需等待并行时数据冲突没有生成随机数据Teardown清理或加随机后缀这张表是我在带新人时最常用的一张内部速查表。每次遇到问题先对照现象找到排查方向不要上来就改用例。结尾部分说说我实践下来的体会。刚开始我把机器人框架当成一个写脚本的工具用着用着发现它真正的价值是“用例即文档”。团队里除了自动化工程师业务分析师、项目经理也都愿意打开log.html看执行结果。后来我又做了一套公共关键字库把登录、下单、数据准备这些高频操作封装成类似“登录系统”“创建订单”这样的业务关键字业务同事甚至可以自己拖拽组成新用例。这才是机器人框架测试自动化最值得投入的地方不是去替换所有人手写脚本而是把测试知识沉淀成语义清晰的关键字积木。第一篇先写到这后面我再接着聊如何自定义Python库和持续集成。未完待续
阅读完成 · 觉得有帮助?
咨询建站