SeleniumBase Case Plan 实战:解析 basic_test 购物车冒烟测试的步骤定义与自动化实现
【免费下载链接】SeleniumBaseAPIs for browser automation, testing, and bypassing bot-detection. Includes CDP Mode: A stealthy configuration for chromium that passes every bot detection test.项目地址: https://gitcode.com/GitHub_Trending/se/SeleniumBase
导读
本文以 examples/case_plans/basic_test.MyTestClass.test_basics.md 为核心,深入讲解 SeleniumBase 的 Case Plan(测试用例计划)文件格式、它与自动化测试脚本 examples/basic_test.py 之间的一一对应关系,以及 Case Plans 生成器(sbase caseplans)背后的实现机制。读完本文,你将掌握如何阅读和编写 Case Plan Markdown 步骤表、如何把人工测试步骤映射为可运行的 SeleniumBase 测试代码,并了解如何用 GUI 生成 Case Plan 模板与case_summary.md汇总文件。
一、Case Plan 文件是什么
Case Plan 是 SeleniumBase 提供的一种"测试用例管理"载体:它以标准 Markdown 表格的形式,把一个自动化测试用例的操作步骤与预期结果组织成人类可读、可直接渲染在 Git 仓库页面上的计划文档。每个 Case Plan 文件对应一个具体的测试函数(TestCase),命名规则为「测试文件.测试类.测试方法」加上.md后缀。
basic_test.MyTestClass.test_basics.md就是一个典型例子,它的标题行即测试地址:
basic_test.py::MyTestClass::test_basics这是 pytest 风格的 Node ID(文件::类::方法),精确指明该计划对应 examples/basic_test.py 中MyTestClass类下的test_basics测试方法。
文件结构与命名规则
从 seleniumbase/console_scripts/sb_caseplans.py 的源码可以看到,Case Plan 文件名的生成规则为:
def get_test_id(display_id): """The id used in various places such as the test log path.""" return ( display_id.replace(".py::", ".").replace("::", ".").replace(" ", "_") )也就是说basic_test.py::MyTestClass::test_basics会被转换为basic_test.MyTestClass.test_basics,再加上.md后缀,即得 examples/case_plans/basic_test.MyTestClass.test_basics.md。该文件存放在测试文件同级的case_plans/子目录中(源码见 sb_caseplans.py)。
二、核心表格逐行解读
该 Case Plan 的核心内容是一张 5 行的 Markdown 步骤表,全表内容如下:
| # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Log in to https://www.saucedemo.com withstandard_user. | Login was successful. | | 2 | Click on theBackpackADD TO CARTbutton. | The button text changed toREMOVE. | | 3 | Click on the cart icon. | TheBackpackis seen in the cart. | | 4 | Remove theBackpackfrom the cart. | TheBackpackis no longer in the cart. | | 5 | Log out from the website. | Logout was successful. |
三列的含义非常直观:
- #:步骤序号,按执行顺序编号;
- Step Description:用自然语言描述"做什么";
- Expected Result:描述"做完后应看到什么",即该步骤的验收标准。
这张表描述的是一个标准的电商购物车冒烟测试闭环:登录 → 加购 → 查看购物车 → 移除商品 → 登出。每个步骤都可以独立作为验收点,任何一个步骤失败,测试都应定位到对应环节。
三、步骤表与自动化源码的映射
Case Plan 的每一步都能在 examples/basic_test.py 中找到对应的自动化实现。下面逐步对照讲解。
Step 1:登录 →goto+type+assert_element
Case Plan 要求"以standard_user登录 saucedemo.com 且登录成功",源码对应:
self.goto("https://www.saucedemo.com") self.type("#user-name", "standard_user") self.type("#password", "secret_sauce\n") self.assert_element("div.inventory_list") self.assert_exact_text("Products", "span.title")其中有两个值得注意的细节:
self.type("#password", "secret_sauce\n")的密码以\n结尾。按仓库内 examples/my_first_test.py 注释确认,self.type()会依次完成"等待元素可见 → 等待可交互 → 清空文本 → 输入文本",如果文本以\n结尾则自动提交表单(等效于按下回车),省去了显式点击登录按钮;assert_element("div.inventory_list")与assert_exact_text("Products", "span.title")双重校验登录成功:前者确认商品列表容器存在,后者确认页面标题精确为Products。assert_exact_text会忽略文本首尾空白(见 my_first_test.py 注释)。
Step 2:点击 Backpack 的 ADD TO CART → CSS 属性子串选择器
Case Plan 要求"点击 Backpack 的 ADD TO CART 按钮,按钮文本变为 REMOVE",源码对应:
self.click('button[name*="backpack"]')这里用的是 CSS 属性子串选择器[name*="backpack"],匹配name属性中包含backpack的按钮,比写死完整id更抗页面结构调整。按钮文本从ADD TO CART变为REMOVE,正是 SeleniumBase 在源码中通过self.click()驱动真实点击后,React 页面状态更新的结果。
Step 3:点击购物车图标 → 容器定位
self.click("#shopping_cart_container a")点击购物车容器内的链接进入购物车页,随后校验:
self.assert_exact_text("Your Cart", "span.title") self.assert_text("Backpack", "div.cart_item")assert_text是子串匹配(而assert_exact_text是精确匹配),这里用于确认div.cart_item中确实出现了Backpack商品文本,与 Case Plan 中"购物车中能看到 Backpack"的预期一致。
Step 4:移除商品 → 文本选择器 + 反向断言
self.click('button:contains("Remove")') # HTML innerText self.assert_text_not_visible("Backpack", "div.cart_item")button:contains("Remove")是 SeleniumBase 特有的HTML innerText 选择器,按按钮可见文本定位,与 Step 2 的属性选择器形成互补;assert_text_not_visible验证Backpack文本不再可见,正好对应 Case Plan 中"Backpack 不再出现在购物车中"的预期结果。
Step 5:登出 → JS 点击隐藏元素
self.js_click("a#logout_sidebar_link") self.assert_element("div#login_button_container")js_click通过 JavaScript 直接触发点击,能够点击普通click难以触及的隐藏元素——这里用来打开侧边栏并触发登出链接(源码注释见 my_first_test.py)。最后断言登录按钮容器重新出现,确认登出成功,与 Case Plan 第 5 步"Logout was successful"闭环。
完整源码
"""Add an item to a shopping cart. Verify. Remove item. Verify.""" from seleniumbase import BaseCase BaseCase.main(__name__, __file__) class MyTestClass(BaseCase): def test_basics(self): self.goto("https://www.saucedemo.com") self.type("#user-name", "standard_user") self.type("#password", "secret_sauce\n") self.assert_element("div.inventory_list") self.assert_exact_text("Products", "span.title") self.click('button[name*="backpack"]') self.click("#shopping_cart_container a") self.assert_exact_text("Your Cart", "span.title") self.assert_text("Backpack", "div.cart_item") self.click('button:contains("Remove")') # HTML innerText self.assert_text_not_visible("Backpack", "div.cart_item") self.js_click("a#logout_sidebar_link") self.assert_element("div#login_button_container")BaseCase.main(__name__, __file__)的作用是让测试既可以用pytest运行,也可以直接用python basic_test.py运行(见 my_first_test.py 注释),二者皆可。
运行方式:
# 方式一:pytest 运行 pytest examples/basic_test.py # 方式二:直接运行脚本 python examples/basic_test.py四、Case Plans 生成机制:sbase caseplans
Case Plan 文件不是只能手写,SeleniumBase 提供了专门的 GUI 生成器,入口脚本为 seleniumbase/console_scripts/sb_caseplans.py。
命令用法
sbase caseplans # 收集当前目录下所有测试 sbase caseplans -k agent # 按关键字过滤(同 pytest -k) sbase caseplans -m marker2 # 按 pytest marker 过滤 sbase caseplans test_suite.py # 指定测试文件 sbase caseplans offline_examples/ # 指定测试目录其实现原理是:main()内部调用python -m pytest --collect-only -q收集所有测试用例(源码见 sb_caseplans.py),把包含::的行解析为测试列表,再打开 Tkinter GUI 供选择(sb_caseplans.py)。
生成 boilerplate 模板
在 GUI 中勾选"还没有 Case Plan 的测试",点击Generate boilerplate Case Plans for selected tests missing them后,每个测试会生成一份默认模板(源码见 sb_caseplans.py),形如:
``proxy_test.py::ProxyTests::test_proxy`` --- | # | Step Description | Expected Result | | - | ---------------- | --------------- | | 1 | Perform Action 1 | Verify Action 1 | | 2 | Perform Action 2 | Verify Action 2 |随后由测试作者把占位内容替换为真实的步骤与预期结果——basic_test.MyTestClass.test_basics.md就是一份已经完成定制("🔵 状态")的 Case Plan。
生成汇总文件case_summary.md
GUI 中的Generate Summary of existing Case Plans按钮会扫描所有case_plans/目录下的计划文件,生成一份聚合的 examples/case_summary.md。生成逻辑会按表格内容自动标注状态图标(源码见 sb_caseplans.py):
| 图标 | 含义 | 判定条件 | | - | - | - | | 🔵 | 已定制步骤表 | 表中不含默认占位文本| 1 | Perform Action 1 | Verify Action 1 || | ⭕ | 仍为默认模板 | 存在占位文本,未填充真实步骤 | | 🚧 | 缺少表格 ||少于 9 个或-少于 3 个,无法构成最小 Markdown 表格 |
当前仓库中basic_test.MyTestClass.test_basics.md属于 🔵(已定制),并已出现在 case_summary.md 的汇总中。注意:case_summary.md生成于启动 GUI 的目录,而单个 Case Plan 文件则生成在各自测试文件旁的case_plans/目录里,两者位置不同。
同类 Case Plan 参考
仓库examples/case_plans/中还有多份同规格的案例,可对照学习不同主题的写法:
- my_first_test.MyTestClass.test_swag_labs.md:完整购物 + 结算流程(对应 examples/my_first_test.py),比
basic_test多了 CHECKOUT、FINISH 两步; - test_login.SwagLabsLoginTests.test_swag_labs_login.md:精简版登录登出(对应 examples/test_login.py);
- test_assert_elements.ListAssertTests.test_assert_list_of_elements.md:元素列表断言类测试;
- shadow_root_test.ShadowRootTest.test_shadow_root.md:Shadow DOM 场景测试。
五、Markdown 表格语法要点
Case Plan 依赖 Markdown 表格渲染,因此对格式有严格要求(完整说明见 help_docs/case_plans.md):
- 管道符、破折号与空格的位置必须正确,否则表格无法渲染;
- 步骤内需要换行时用
<br />,例如结算步骤:Click on the ``CHECKOUT`` button. <br /> Enter user details and click ``CONTINUE``.; - 需要留空步骤内容时,在管道符之间放一个空格,即
| |; - 第一行测试地址用双反引号包裹(如
basic_test.py::MyTestClass::test_basics),第二行为---分隔线,之后紧跟表格。
六、小结
basic_test.MyTestClass.test_basics.md这份 Case Plan 以 5 行 Markdown 表格浓缩了 SeleniumBase 电商冒烟测试的核心链路,而 examples/basic_test.py 用 15 行代码将其完整落地。两者共同构成了"人工可读的计划 + 机器可执行的脚本"的双轨测试管理方式:Case Plan 面向评审与沟通,源码面向回归与 CI。配合 sbase caseplans 生成器,团队可以低成本地为既有测试批量建立计划文档,并通过case_summary.md一目了然地掌握所有用例的计划完成状态。
【免费下载链接】SeleniumBaseAPIs for browser automation, testing, and bypassing bot-detection. Includes CDP Mode: A stealthy configuration for chromium that passes every bot detection test.项目地址: https://gitcode.com/GitHub_Trending/se/SeleniumBase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考