Python+RobotFramework接口自动化测试:从环境搭建到CI/CD集成实战
1. 项目概述为什么选择PythonRobotFramework做接口自动化如果你正在为团队或自己的项目寻找一套稳定、易上手且能快速产出的接口自动化测试方案那么PythonRobotFramework这个组合大概率会成为你的首选。我最早接触这套框架是在一个敏捷迭代非常快的电商项目中当时团队测试资源紧张后端接口变动频繁手工回归测试的压力巨大。我们尝试过用纯Python写Requests库的脚本也看过一些其他测试框架最终落地RobotFramework核心原因就三个关键字驱动带来的低门槛、丰富的生态库、以及清晰易读的测试报告。简单来说RobotFramework后文简称RF是一个基于Python的、通用的自动化测试框架。它采用表格化的测试用例语法通过“关键字”来封装底层操作。对于接口测试你不需要从零开始写HTTP请求、解析JSON响应、做断言判断这些都被封装成了像“发送请求”、“响应状态码应为”、“响应体应包含”这样的自然语言关键字。测试人员甚至开发人员只要理清业务逻辑就能像搭积木一样编写出可执行的测试用例。而Python在这里扮演了“发动机”和“扩展工具箱”的角色——RF本身由Python编写其强大的第三方库如RequestsLibrary也是Python库当内置关键字不够用时你还能用Python轻松自定义关键字实现任何复杂逻辑。这套组合拳解决了什么痛点第一降低了自动化测试的参与门槛让业务测试人员能快速上手贡献用例第二统一的框架和报告格式便于团队协作和知识沉淀第三利用Python的灵活性既能享受RF的便捷又不失应对复杂场景的能力。接下来我将从一个完整的项目实操角度带你从零搭建环境到编写一套健壮的接口自动化测试套件。2. 环境搭建与核心工具选型工欲善其事必先利其器。一个稳定、隔离的Python环境是这一切的基础。我强烈建议使用虚拟环境来管理你的RF项目依赖这能避免不同项目间的库版本冲突。2.1 Python环境与虚拟环境配置首先你需要安装Python。访问Python官网下载3.7及以上版本推荐3.8或3.9兼容性和稳定性都较好的安装包。安装时务必勾选“Add Python to PATH”选项这样就能在命令行中直接使用python和pip命令。安装完成后打开命令行Windows的CMD或PowerShellMac/Linux的Terminal验证安装python --version pip --version接下来我们使用venv创建项目专属的虚拟环境。在你的项目目录下例如D:\projects\api-auto-test执行# Windows python -m venv venv # Mac/Linux python3 -m venv venv这会在当前目录创建一个名为venv的文件夹里面包含了一个独立的Python解释器和pip。激活虚拟环境# Windows (CMD) venv\Scripts\activate.bat # Windows (PowerShell) venv\Scripts\Activate.ps1 # 可能需要先执行 Set-ExecutionPolicy RemoteSigned # Mac/Linux source venv/bin/activate激活后命令行提示符前会出现(venv)字样表示你已进入该虚拟环境所有后续的包安装都仅限于此环境。注意很多初学者会忽略虚拟环境直接在系统Python中安装各种包后期极易出现“在我机器上是好的”这类问题。养成每个项目独立环境的习惯是走向专业化的第一步。2.2 RobotFramework及其关键库的安装在激活的虚拟环境中我们开始安装核心框架和库。使用pip安装时建议使用国内镜像源以加速下载例如清华源。pip install robotframework -i https://pypi.tuna.tsinghua.edu.cn/simple这是RF框架本身。接下来安装接口自动化最核心的库——RequestsLibrary。它是对Python著名HTTP库requests的RF封装提供了发送HTTP请求、处理响应的全套关键字。pip install robotframework-requests -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后可以顺手安装几个提高效率的辅助库robotframework-databaselibrary 用于数据库验证如检查接口是否写入了正确数据。robotframework-jsonlibrary 专门用于处理和验证JSON数据的库比内置关键字更强大。robotframework-faker 用于生成测试用的假数据姓名、地址、邮箱等。pip install robotframework-databaselibrary robotframework-jsonlibrary robotframework-faker -i https://pypi.tuna.tsinghua.edu.cn/simple2.3 编辑器的选择与配置编写RF测试用例本质上是编写.robot文件。你可以使用任何文本编辑器但一个配置好的IDE能极大提升效率。我的首选是VS Code因为它轻量、免费且插件生态丰富。在VS Code中你需要安装以下插件Robot Framework Language Server 提供语法高亮、代码补全、关键字跳转、格式化等核心功能是RF开发的必备神器。Python 用于编写和调试自定义的Python库。安装完插件后在VS Code中打开你的项目文件夹。你可以通过CtrlShiftP打开命令面板输入“Python: Select Interpreter”然后选择你刚才创建的虚拟环境路径下的python.exe例如.\venv\Scripts\python.exe。这样VS Code就会使用项目虚拟环境中的Python和已安装的RF库来提供智能提示。3. 项目结构与第一个测试用例一个清晰的项目结构有助于长期维护。我推荐如下结构api-auto-test/ ├── venv/ # Python虚拟环境目录.gitignore忽略 ├── testsuites/ # 测试套件目录 │ ├── __init__.robot # 套件初始化文件可选 │ ├── smoke_test.robot # 冒烟测试套件 │ └── regression_test.robot # 回归测试套件 ├── resources/ # 资源文件目录 │ ├── common.robot # 公共关键字和变量 │ ├── api_resources.robot # 接口相关资源 │ └── database_resources.robot # 数据库相关资源 ├── libraries/ # 自定义Python库目录 │ └── my_custom_library.py ├── variables/ # 变量文件目录 │ ├── env_config.py # 环境配置不同环境的URL、账号等 │ └── global_vars.py # 全局变量 ├── data/ # 测试数据文件如JSON, CSV ├── results/ # 测试报告输出目录.gitignore忽略 └── README.md # 项目说明文档现在我们来创建第一个测试用例文件testsuites/smoke_test.robot。*** Settings *** Documentation 接口自动化冒烟测试套件 Library RequestsLibrary Library Collections Resource ../resources/common.robot Suite Setup Initialize Test Environment Suite Teardown Cleanup Test Environment *** Variables *** ${BASE_URL} https://jsonplaceholder.typicode.com # 一个免费的测试API网站 *** Test Cases *** 验证获取帖子列表接口基本功能 [Documentation] 测试GET /posts 接口验证状态码和返回数据结构 [Tags] smoke get Create Session jsonplaceholder ${BASE_URL} ${response} GET On Session jsonplaceholder /posts # 断言状态码为200 Should Be Equal As Strings ${response.status_code} 200 # 断言响应体是列表格式 ${response_json} Set Variable ${response.json()} ${type} Evaluate type($response_json).__name__ Should Be Equal ${type} list # 断言列表不为空且第一个元素包含预期的字段 Length Should Be ${response_json} ${100} # 该接口固定返回100条 Dictionary Should Contain Key ${response_json[0]} id Dictionary Should Contain Key ${response_json[0]} title Log 获取帖子列表成功共${100}条数据。 levelINFO 验证创建新帖子接口 [Documentation] 测试POST /posts 接口 [Tags] smoke post Create Session jsonplaceholder ${BASE_URL} {headers} Create Dictionary Content-Typeapplication/json {data} Create Dictionary titleRobotFramework Test bodyThis is a test post. userId1 ${response} POST On Session jsonplaceholder /posts json${data} headers${headers} Should Be Equal As Strings ${response.status_code} 201 ${response_json} Set Variable ${response.json()} Dictionary Should Contain Key ${response_json} id Should Be Equal As Strings ${response_json[title]} RobotFramework Test Log 新建帖子成功ID为${response_json[id]} levelINFO *** Keywords *** Initialize Test Environment Log 测试环境初始化完成... levelINFO Cleanup Test Environment Delete All Sessions Log 清理所有HTTP会话。 levelINFO这个用例文件展示了RF的基本结构Settings 定义文档、引入库和资源文件、设置套件级别的初始化和清理。Variables 定义套件内使用的变量如${BASE_URL}。Test Cases 具体的测试用例每个用例包含步骤关键字和断言。Keywords 用户自定义的关键字用于封装可复用的操作逻辑。运行这个测试套件在项目根目录下执行robot --outputdir results testsuites/smoke_test.robot命令执行后会在results文件夹下生成三个文件output.xml,log.html,report.html。用浏览器打开report.html你就能看到清晰直观的测试报告包括通过/失败状态、每个步骤的详细日志和时间。4. 核心关键字详解与高级用法掌握了基础用例编写后我们需要深入理解RequestsLibrary的核心关键字和如何组织更复杂的测试逻辑。4.1 HTTP请求关键字的灵活运用RequestsLibrary提供了对应HTTP各种方法的关键字最常用的是GET On Session和POST On Session。但除此之外还有一些高级用法1. 会话管理Create Session用于创建一个持久化的HTTP会话可以复用TCP连接提升性能并自动管理cookies。为不同系统或模块创建不同的会话名是良好实践。Create Session auth_server https://auth.example.com verify${True} Create Session api_gateway https://api.example.com/v12. 处理请求参数与头信息Params查询参数 对于GET请求使用params参数。${params} Create Dictionary page1 limit20 ${response} GET On Session api_gateway /users params${params}Data表单数据 对于application/x-www-form-urlencoded格式的POST使用data参数。{form_data} Create Dictionary usernametestuser passwordsecret ${response} POST On Session auth_server /login data${form_data}JsonJSON数据 对于application/json格式使用json参数最常用库会自动序列化字典并设置正确的Content-Type。{payload} Create Dictionary nameNew Item price99.9 ${response} POST On Session api_gateway /items json${payload}Headers自定义头 使用headers参数传递自定义HTTP头。{headers} Create Dictionary AuthorizationBearer ${TOKEN} X-Custom-HeaderMyValue ${response} GET On Session api_gateway /profile headers${headers}3. 文件上传使用files参数其值是一个字典键是表单字段名值是文件路径。{files} Create Dictionary file${CURDIR}/test_data/upload.jpg ${response} POST On Session api_gateway /upload files${files}4.2 响应断言与数据提取发送请求后对响应的验证是测试的核心。RF内置的BuiltIn库和Collections库提供了丰富的断言关键字。1. 基础状态码与内容断言Should Be Equal As Strings ${response.status_code} 200 Should Contain ${response.text} success2. JSON响应体的深度断言这是接口测试的重中之重。通常我们会将JSON响应体转换为Python字典或列表进行操作。${resp_json} Set Variable ${response.json()} # 验证整个响应体结构严格匹配 Should Be Equal ${resp_json} ${expected_dict} # 验证部分字段 Should Be Equal As Strings ${resp_json[data][userId]} 123 # 验证字段是否存在 Dictionary Should Contain Key ${resp_json[data]} email # 验证列表长度 Length Should Be ${resp_json[data][items]} 5 # 验证列表中某个元素满足条件使用循环或“Get Matches” FOR ${item} IN {resp_json[data][items]} Run Keyword If ${item[id]} 100 ... Log Found target item: ${item} END3. 使用JSONLibrary进行更强大的JSON验证当JSON结构非常复杂时JSONLibrary的Validate Json和Get Value From Json关键字非常有用。Library JSONLibrary ${schema} Get File ${CURDIR}/data/user_schema.json Validate Json ${response.text} ${schema} # 根据JSON Schema验证结构 ${emails} Get Value From Json ${response.text} $..email # 使用JsonPath提取所有email Should Not Be Empty ${emails}4. 响应时间断言性能测试中我们常需要断言接口响应时间。${timeout} Set Variable 3 ${resp} GET On Session api_gateway /health timeout${timeout} # 注意RequestsLibrary的timeout参数是连接读取的总超时。 # 如果需要精确测量可以使用${resp.elapsed}对象是一个datetime.timedelta ${elapsed_ms} Evaluate int($resp.elapsed.total_seconds() * 1000) Should Be True ${elapsed_ms} 500 msg接口响应时间超过500ms: ${elapsed_ms}ms4.3 封装可复用的自定义关键字当多个测试用例有相同的操作序列时就应该将其封装成自定义关键字。这是提升脚本可维护性的关键。我们可以在resources/common.robot中定义。示例封装一个带认证的请求关键字*** Settings *** Library RequestsLibrary Library Collections *** Keywords *** 发送带Token的GET请求 [Arguments] ${alias} ${uri} ${expected_status}200 [Documentation] 使用指定会话发送GET请求并自动添加认证Token最后进行状态码断言。 ... ... *Args*: ... - alias: 已创建的会话别名。 ... - uri: 请求路径。 ... - expected_status: 期望的HTTP状态码默认为200。 ... ... *Returns*: 响应对象。 ${token} Get Auth Token # 假设这是一个获取Token的关键字 {headers} Create Dictionary AuthorizationBearer ${token} ${response} GET On Session ${alias} ${uri} headers${headers} Should Be Equal As Strings ${response.status_code} ${expected_status} [Return] ${response} 发送带Token的POST请求 [Arguments] ${alias} ${uri} ${payload}${EMPTY} ${expected_status}201 [Documentation] 发送POST请求支持JSON和表单数据。 ${token} Get Auth Token {headers} Create Dictionary AuthorizationBearer ${token} # 判断payload类型自动设置Content-Type ${is_dict} Run Keyword And Return Status Should Be Dictionary ${payload} IF ${is_dict} Set To Dictionary ${headers} Content-Typeapplication/json ${response} POST On Session ${alias} ${uri} json${payload} headers${headers} ELSE Set To Dictionary ${headers} Content-Typeapplication/x-www-form-urlencoded ${response} POST On Session ${alias} ${uri} data${payload} headers${headers} END Should Be Equal As Strings ${response.status_code} ${expected_status} [Return] ${response}在用例中你就可以这样简洁地调用${resp} 发送带Token的GET请求 api_gateway /user/profile ${resp_json} Set Variable ${resp.json()} # ... 其他断言5. 测试数据驱动与动态参数化固定的测试数据无法满足覆盖多种业务场景的需求。RF支持强大的数据驱动测试主要有两种方式使用[Template]的测试用例模板和使用外部数据文件。5.1 使用[Template]实现参数化测试这种方式适用于测试步骤完全相同只有输入数据和预期结果不同的场景。我们将测试逻辑定义为一个“模板关键字”然后用一个测试用例来驱动多组数据。*** Test Cases *** 用户登录功能参数化测试 [Template] 验证登录接口 # 用户名 密码 期望状态码 期望消息包含 valid_user valid_pass 200 success invalid_user valid_pass 401 Unauthorized valid_user wrong_pass 401 Unauthorized ${EMPTY} valid_pass 400 username valid_user ${EMPTY} 400 password *** Keywords *** 验证登录接口 [Arguments] ${username} ${password} ${exp_status} ${exp_msg_contains} {data} Create Dictionary username${username} password${password} ${response} POST On Session auth_server /login json${data} expected_status${exp_status} Run Keyword If ${response.status_code} ! 401 # 401可能没有消息体 ... Should Contain ${response.text} ${exp_msg_contains}运行这个用例RF会为每一行数据执行一次验证登录接口关键字并在报告中清晰展示每一次迭代的结果。5.2 使用外部文件CSV/Excel驱动测试对于数据量更大、更复杂的场景将测试数据放在外部文件如CSV、Excel中是更好的选择。我们可以使用Python的csv库或openpyxl库来读取数据并在RF中调用。首先创建一个Python工具库libraries/data_loader.pyimport csv import json from robot.api import logger class DataLoader: 用于加载外部测试数据的工具类 def load_test_data_from_csv(self, file_path): 从CSV文件加载测试数据返回字典列表。 test_data [] with open(file_path, r, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: test_data.append(row) logger.info(fLoaded {len(test_data)} rows of test data from {file_path}) return test_data def get_data_for_test_case(self, data_list, case_name): 从数据列表中根据用例名筛选数据。 for data in data_list: if data.get(test_case) case_name: return data return None在RF资源文件中引入并使用*** Settings *** Library ../libraries/data_loader.py *** Variables *** ${DATA_FILE} ${CURDIR}/../data/test_cases.csv *** Keywords *** 加载测试数据 ${all_data} DataLoader.Load Test Data From Csv ${DATA_FILE} Set Suite Variable ${ALL_TEST_DATA} ${all_data} 获取当前用例数据 [Arguments] ${case_name} ${case_data} DataLoader.Get Data For Test Case ${ALL_TEST_DATA} ${case_name} [Return] ${case_data}在测试套件中*** Settings *** Suite Setup 加载测试数据 Test Setup 获取测试数据 *** Test Cases *** 创建订单测试 [Documentation] 使用CSV中的数据驱动测试 Log 测试数据: ${TEST_DATA} # 使用 ${TEST_DATA[product_id]}, ${TEST_DATA[quantity]} 等作为参数 ${payload} Create Dictionary productId${TEST_DATA[product_id]} quantity${TEST_DATA[quantity]} ${response} 发送带Token的POST请求 api_gateway /orders payload${payload} # ... 使用 ${TEST_DATA[expected_order_id]} 进行断言 *** Keywords *** 获取测试数据 ${TEST_DATA} 获取当前用例数据 ${TEST_NAME} # ${TEST_NAME}是RF内置变量表示当前用例名 Set Test Variable ${TEST_DATA}这种方式将测试数据与测试逻辑完全分离维护数据只需编辑CSV文件非常适合业务规则复杂的场景。6. 测试套件组织与执行策略当用例数量成百上千时如何组织和管理它们就变得至关重要。RF通过目录和文件结构来组织测试套件。6.1 分层与模块化设计我推荐按业务域或功能模块来划分测试套件目录。例如testsuites/ ├── user_management/ # 用户管理模块 │ ├── __init__.robot # 可以在此初始化用户管理模块的专用会话 │ ├── login_logout.robot │ ├── profile.robot │ └── registration.robot ├── order_processing/ # 订单处理模块 │ ├── __init__.robot │ ├── create_order.robot │ ├── payment.robot │ └── order_query.robot └── product_catalog/ # 商品目录模块 ├── __init__.robot ├── search.robot └── detail.robot每个目录下的__init__.robot文件是该目录套件的初始化文件可以在这里定义该模块公用的Suite Setup和Suite Teardown以及引入公共资源。6.2 标签Tags的妙用RF的标签功能是进行用例筛选和分类的神器。你可以在测试用例或套件级别使用[Tags]来打标签。*** Test Cases *** 验证VIP用户专属接口 [Tags] smoke vip regression # ... 测试步骤 验证新用户注册流程 [Tags] regression p1 # ... 测试步骤 性能压测_查询接口 [Tags] performance nightly # ... 测试步骤通过标签你可以灵活地选择要运行的测试集# 只运行冒烟测试 robot --include smoke testsuites/ # 运行除了性能测试外的所有用例 robot --exclude performance testsuites/ # 运行优先级为p1的回归测试 robot --include regressionANDp1 testsuites/在CI/CD流水线中你可以配置不同的任务每次代码提交触发--include smoke的快速冒烟测试每晚定时触发完整的--exclude performance回归测试每周触发一次--include performance的性能测试。6.3 变量文件的动态加载不同环境开发、测试、预生产的配置如URL、账号、数据库连接肯定不同。硬编码在脚本里是灾难。使用变量文件是解决方案。创建variables/env_config.py# 开发环境配置 DEV_CONFIG { base_url: https://dev-api.example.com, db_host: dev-db.example.com, db_user: test_user, db_password: test_pass_123, admin_user: admin_dev, admin_pw: admin_dev_pw } # 测试环境配置 TEST_CONFIG { base_url: https://test-api.example.com, db_host: test-db.example.com, db_user: test_user, db_password: test_pass_456, admin_user: admin_test, admin_pw: admin_test_pw } # 通过环境变量决定使用哪个配置 import os env os.getenv(AUTO_TEST_ENV, TEST).upper() if env DEV: config DEV_CONFIG elif env TEST: config TEST_CONFIG else: raise ValueError(fUnknown environment: {env}) # 将这些变量暴露给RF BASE_URL config[base_url] DB_HOST config[db_host] DB_USER config[db_user] DB_PASSWORD config[db_password] ADMIN_USER config[admin_user] ADMIN_PW config[admin_pw]在运行测试时通过--variablefile参数指定变量文件并通过环境变量切换配置# Windows (CMD) set AUTO_TEST_ENVDEV robot --variablefile variables/env_config.py testsuites/ # Mac/Linux export AUTO_TEST_ENVDEV robot --variablefile variables/env_config.py testsuites/在RF脚本中你可以直接使用这些变量如${BASE_URL}RF会自动从Python变量文件中加载。7. 报告生成、日志管理与持续集成自动化测试的最终价值在于快速反馈。清晰详尽的报告和与CI/CD工具的集成是关键。7.1 定制化报告与日志RF默认生成的report.html和log.html已经非常强大。但我们可以通过命令行参数进行一些优化# 设置报告标题 robot --name 订单服务接口回归测试 --reporttitle 测试报告 --logtitle 详细日志 testsuites/ # 合并多次运行的结果用于分模块运行后汇总 rebot --outputdir final_results --merge output1.xml output2.xml # 为报告添加元数据如版本号、构建ID robot --metadata Version:1.2.3 --metadata Build:${BUILD_NUMBER} testsuites/在测试用例或关键字中善用Log关键字输出有意义的调试信息并指定级别INFO,DEBUG,WARN。在log.html中你可以通过筛选级别来快速定位问题。Log 开始处理用户订单订单ID: ${order_id} levelINFO ${response} 发送请求 ${payload} Log 接口响应: ${response.text} levelDEBUG # DEBUG级别信息默认不显示在报告中需通过--loglevel DEBUG开启7.2 与持续集成工具集成将RF测试集成到Jenkins、GitLab CI、GitHub Actions等CI/CD平台是标准操作。核心步骤通常包括准备环境 在CI Agent上安装Python、RF及项目依赖通常通过requirements.txt和pip install -r requirements.txt。执行测试 运行robot命令并指定输出目录。收集结果 将生成的output.xml、report.html、log.html作为构建产物存档。报告展示 使用插件如Jenkins的Robot Framework plugin在Jenkins界面直接展示趋势图和报告详情。一个简单的Jenkins Pipeline脚本示例pipeline { agent any stages { stage(Checkout) { steps { git branch: main, url: https://your-git-repo.git } } stage(Setup) { steps { sh python -m pip install --upgrade pip sh pip install -r requirements.txt } } stage(Run Tests) { steps { sh export AUTO_TEST_ENVTEST robot --outputdir results --variablefile variables/env_config.py testsuites/ } } } post { always { archiveArtifacts artifacts: results/**, fingerprint: true robot outputPath: results/output.xml } } }7.3 常见问题排查与调试技巧即使经验丰富也会遇到测试失败的情况。以下是一些快速定位问题的思路连接/超时问题现象Resolving timed out或ConnectionError。排查 首先检查网络连通性ping目标主机检查目标服务是否启动检查防火墙规则。在RF中可以尝试增加timeout参数或使用Create Session时设置verify${False}仅用于测试环境绕过SSL证书验证。响应断言失败现象 状态码或响应内容与预期不符。排查 首先在log.html中查看完整的请求和响应详情。使用Log关键字打印出实际的响应体${response.text}与预期值仔细对比。常见原因包括请求参数格式错误JSON vs FormData、请求头缺失如Content-Type,Authorization、接口逻辑实际已变更。变量作用域问题现象 在某个关键字里设置的变量在另一个关键字里获取不到。排查 牢记RF的变量作用域规则。Set Variable创建的变量默认是局部变量。如果需要在关键字间共享使用Set Test Variable 在当前测试用例内有效。Set Suite Variable 在当前测试套件内有效。Set Global Variable 全局有效谨慎使用。 在自定义Python库中如果需要修改RF的变量可以使用BuiltIn().set_test_variable(var_name, value)。关键字未找到或库导入失败现象No keyword with name XXX found.或Importing test library failed。排查检查库的拼写和大小写。确认库已安装在当前Python环境虚拟环境中。对于自定义Python库检查文件路径是否正确以及类名是否与文件名一致。查看详细的错误堆栈通常会有更具体的导入错误信息。测试数据问题现象 数据驱动测试时某一行数据失败。排查 在模板关键字的最开始用Log打印出当前迭代的所有输入参数。确认数据文件如CSV的编码、分隔符是否正确数据中是否包含特殊字符如逗号、引号需要转义。一个实用的调试技巧是在定位复杂问题时可以暂时在命令行中使用--loglevel DEBUG运行测试这会输出最详尽的内置库和关键字执行信息。或者在怀疑的代码段前后使用Log关键字输出关键变量的值这是最直接有效的方法。最后保持测试用例的独立性每个用例不依赖其他用例的状态和幂等性重复执行结果相同是编写可维护自动化脚本的黄金法则。这意味着每个用例开始前可能需要准备测试数据如创建一个测试用户结束后清理数据删除该用户。利用好Suite Setup和Test Teardown来完成这些准备工作能让你的自动化测试更加稳定可靠。