news 2026/9/20 14:10:43

Python+Selenium实战:TPshop商城注册登录自动化测试入门

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python+Selenium实战:TPshop商城注册登录自动化测试入门

简介:《Python+Selenium+Chrome 自动化测试 TPshop 商城项目实战(一)——注册、登录练习》是一份面向 Web 自动化测试初学者的实战型 PDF。内容围绕 TPshop 商城注册与登录流程展开,系统讲解 Selenium 模块导入、Chrome 驱动实例化、页面打开、元素定位、文本输入、状态校验、隐式等待与显式等待,以及 JavaScript 滚动执行等关键操作,并通过示例代码演示从注册到登录的完整自动化测试过程。资源包为 1 个 PDF 文件,大小约 97KB,内容精炼、结构清晰。目前已有 2431 人学习/下载,是入门 Web UI 自动化测试的实用参考资料。读者可从中获取完整的功能测试分解步骤,学习如何通过错误信息定位验证码、密码格式、两次密码一致性等问题,并掌握滚动页面、处理弹窗、后退导航等实战技巧,便于迁移到其他 Web 项目的自动化测试中。 很多人问我,web自动化测试到底怎么上手最快,我的答案一直没变:别在demo上耗,直接拿一个真实项目跑起来。用python+selenium+chrome这套组合,把TPshop商城的前台注册和登录流程做成自动化脚本,是我比较推荐的一条入门路径。TPshop是一个开源商城系统,本地部署之后页面结构稳定、业务完整,非常适合拿来练习元素定位、等待、断言这些基本功。这篇实战笔记就把环境准备、用例设计、脚本实现和常见坑整个过一遍,给正准备动手的朋友做个参照。

1. 项目背景与测试环境准备

1.1 为什么选TPshop练手

TPshop是ThinkPHP开发的开源B2C商城系统,虽然商业项目也会选用,但对我们练习自动化来说,最重要的是两点:一是环境可控,二是业务齐全。本地搭好之后,注册、登录、购物车、下单、个人中心这些模块随便折腾,脚本写错也不会影响别人。相比直接用线上商城或公开演示站,TPshop不用担心对方改版、封IP、验证码升级,测试数据也可以随便造,这对自动化练习太友好了。

我最早学Selenium时也在各种网站上试过,但效果很差——页面元素今天能定位到,明天就变了,脚本跑两天就废。后来换成TPshop本地部署,一口气把注册、登录、商品搜索、加入购物车全写了,才算真正把自动化测试的套路摸清楚。如果你是刚开始学,我建议你也先从注册、登录这两个模块入手,因为这两个业务覆盖了表单操作、按钮点击、页面跳转、错误提示断言等常见场景,学会了,后面写别的模块就是复制粘贴加改定位。

1.2 环境版本匹配:Python、Selenium、ChromeDriver,一个都不能错

环境准备是老生常谈,但版本不匹配的坑我见得太多了。先说结论:Python用3.7以上,Selenium用4.x,Chrome浏览器用最新稳定版,ChromeDriver必须和浏览器的大版本号对应。怎么查?打开Chrome,地址栏输入chrome://version,看“Google Chrome”那行,比如120.0.6099.109,那么ChromeDriver就去下载120.0.6099开头的版本。

这里有一个容易踩的坑:如果你还在用Windows 7,Chrome官方早就停止支持了,最高只能装到109版本,ChromeDriver也得选109对应的版本,不能用新的120+版本。很多新手下载了新版驱动,在win7上跑起来直接报“此版本浏览器不支持”之类的错误,其实不是代码问题,是版本问题。另外,Selenium4里推荐用webdriver.Chrome(service=Service(...))方式指定驱动路径,你可以手动下载解压后放到固定目录,也可以用webdriver-manager自动管理,但国内网络环境下自动下载偶尔会失败,所以我更建议手动放好,至少知道driver在哪。

from selenium import webdriver from selenium.webdriver.chrome.service import Service service = Service(r"D:\driver\chromedriver.exe") driver = webdriver.Chrome(service=service) driver.get("http://localhost/tpshop") driver.maximize_window()

很多老教程写的是webdriver.Chrome(),在Selenium4里不指定service也能跑,前提是chromedriver已经加入PATH。把driver放到Python安装目录的Scripts文件夹下也算一种方式,但多人协作时容易乱,各写各的路径,反而增加排查成本。我个人的习惯是把driver放在项目目录下的driver/文件夹里,用Service去指定,这样换机器时只要同步一下代码,修改一个路径变量就行,不用动系统环境变量。

2. 被测系统分析与测试用例设计

2.1 TPshop注册/登录模块功能梳理

写脚本前一定要先把被测功能梳理清楚。TPshop前台注册、登录的页面逻辑大概是:点击“免费注册”进入注册页,填写手机号、密码、确认密码,有的版本还有图形验证码和短信验证;登录页支持手机号/用户名/邮箱登录,输入密码后勾选“记住用户名”可以直接登录。不同版本界面略有差异,但底层流程基本一致。

我习惯把功能点列成一张表,写脚本时对照着看,避免漏用例。

模块功能点自动化关注点
注册合法手机号+两次密码一致输入框定位、注册成功提示、页面跳转
注册重复手机号错误提示文案、停留当前页
注册两次密码不一致前端校验提示
注册密码长度过短校验规则断言
登录正确账号密码登录成功、用户名显示
登录错误密码密码错误提示
登录空提交必填校验提示

列出来后,你会发现注册和登录的自动化用例并不复杂,真正花时间的是定位元素和等元素出现。对了,TPshop注册成功后会跳到登录页,或者直接显示成功提示,不同版本不一样,跑脚本之前先手动点一遍,把实际流程记录下来,再写断言。这里最关键的一点是预期结果不能写得模棱两可,否则后面断言根本不知道要等哪个元素。

2.2 先写用例再写脚本,避免脚本越写越乱

很多新手一上来就开浏览器写代码,结果写到后面逻辑全缠在一起。我的习惯是先把用例用中文写出来,不写代码逻辑,就写前置条件、操作步骤、预期结果。比如正常注册用例可以这么写:前置条件——访问注册页;步骤——1.输入未注册手机号,2.输入密码123456,3.确认密码123456,4.点击注册按钮;预期结果——页面出现“注册成功”提示,随后跳转到登录页。

有了这个描述,代码只是把每一步翻译成Selenium操作。后面如果脚本挂了,也能对照用例检查是代码写错了还是被测系统真有bug。这一点在真实项目里特别重要,因为自动化测试跑起来,失败信息要么是定位失败,要么是断言失败,用例能帮我们快速区分是脚本问题还是业务问题。你也可以把用例维护在Excel、xmind或者禅道里,但练手阶段最直接的方法是写在注释里,脚本可读性会好很多。

3. 注册模块自动化脚本实现

3.1 元素定位:优先id/name,不行再xpath

TPshop的表单元素还算规整,很多输入框都带有name属性,这就好办多了。按F12打开开发者工具,点左上角箭头选中输入框,就能看到元素的属性。注册页的手机号输入框一般长这样:<input name="mobile" ...>,密码框是<input name="password" ...>,确认密码框是<input name="password2" ...>。用Selenium定位时,优先用id、name,没有的话再用class_name或xpath。

定位原则很简单:哪个属性稳定且唯一就用哪个。不要一上来就复制浏览器自动生成的绝对xpath,/html/body/div[2]/form/div[1]/input这种,页面只要加一个div就全断。更好的是用相对路径加属性,比如//input[@name='mobile'],既简洁又稳定。注册按钮可能是<a>标签带class,也可能直接是<input type="submit">,定位时要注意标签类型,不要想当然用CLASS_NAME

from selenium import webdriver from selenium.webdriver.common.by import By driver.find_element(By.NAME, "mobile").send_keys("13800138000") driver.find_element(By.NAME, "password").send_keys("123456") driver.find_element(By.NAME, "password2").send_keys("123456") driver.find_element(By.CLASS_NAME, "reg_btn").click()

这里send_keys前如果上一次跑过有残留数据,最好先clear()一下,防止输入框里已经有内容。我一般会在send_keys前加一句driver.find_element(...).clear(),或者用Keys.CONTROL + 'a'组合键全选再删除,保证每次输入都是干净的。还有一种情况是输入框自带默认提示文字,直接send_keys会在默认文本后面追加,导致手机号位数不对,所以清理这一步不要偷懒。

3.2 验证码处理与测试数据准备

验证码是自动化最头疼的部分。TPshop默认可能开启了图形验证码和短信验证码,如果你跑脚本时发现按钮点了没反应,大概率就是卡在验证码上。我的处理方式分三种:第一,有测试环境权限的话,直接去后台关闭验证码;第二,如果开发留了“万能验证码”,脚本里填万能码;第三,通过接口造数据或绕过校验,但这是后端联调做的事,不推荐在UI自动化里折腾。

短信验证码也一样,自动化不要试图真的接收短信,最好和开发约定一个测试接口或者万能短信验证码。如果你想把短信验证码的流程也自动化,可以考虑用代理或数据库去拿验证码,但复杂度会高不少,而且不稳定,个人练习阶段不建议碰。图形验证码的自动化也不是不能做,用OCR识别是常见的思路,但TPshop的验证码可能带干扰线,识别率不高,还是关闭或预留万能码最省事。

再一个坑是手机号数据。注册用例如果每次都用同一个手机号,第二次跑就会提示“手机号已注册”。所以测试数据要生成不重复的。临时做法可以用时间戳后8位拼上运营商前缀:

import time mobile = "139" + str(int(time.time()))[-8:] print(mobile)

这样每次跑注册脚本都能生成一个大概率不重复的手机号。当然,理想做法是把手机号维护在Excel或数据库里,跑完后清理数据,但对于新手练习,动态生成最简单。如果你在跑完用例后希望保留数据,也可以把生成的手机号和密码写到日志里,方便后续登录用例直接用。

3.3 注册流程完整代码与断言

完整写一个注册函数,把等待、点击、断言都带上。TPshop注册成功后,页面上通常会弹一个toast提示,比如“恭喜您注册成功”。我们用WebDriverWait等待这个提示元素出现,然后取文本断言。

from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def test_register(driver): driver.get("http://localhost/tpshop/index.php/Home/User/reg.html") mobile = "139" + str(int(time.time()))[-8:] driver.find_element(By.NAME, "mobile").send_keys(mobile) driver.find_element(By.NAME, "password").send_keys("123456") driver.find_element(By.NAME, "password2").send_keys("123456") driver.find_element(By.CLASS_NAME, "reg_btn").click() toast = WebDriverWait(driver, 10).until( EC.visibility_of_element_located((By.CLASS_NAME, "layui-layer-content")) ) text = toast.text assert "成功" in text, f"注册失败,提示:{text}"

注意toast的class名称以实际页面为准,有可能叫tipslayui-layer-content。我写这个例子时默认是常见的Layer弹层组件,如果跑的时候定位不到,去页面里看一下真实class。还有,如果注册成功会跳转页面,toast一闪而过,等待条件可以换成“页面URL包含login”或“登录按钮可见”,要根据实际表现选断言点。断言语句最好带上错误提示信息,用assert 条件, "说明"的格式,这样测试报告里能看到失败原因,而不是只有一个AssertionError。

4. 登录模块自动化脚本实现

4.1 登录用例与数据准备

登录模块相对简单,但越简单越容易在断言上偷懒。常见做法是登录成功后随便等两秒就完事,这不行,我们要断言登录后的页面元素。TPshop登录成功后,右上角通常会显示用户名或“退出”按钮,用EC.visibility_of_element_located等这个元素出现,再取文本做断言。

测试数据方面,建议先在系统里手动注册或通过SQL插入一个固定账号,比如13800138001 / 123456。为什么不用随机账号?因为登录脚本的职责是验证登录功能,而不是验证注册,每次都用固定账号,数据稳定,断言结果也更可控。固定账号的密码建议满足系统强度要求,太简单可能被校验拦截,反而干扰用例。

我一般会把账号密码放到一个配置文件里,比如config.initestdata.yaml,脚本通过读取文件获取,而不是硬编码到代码中。这样以后换环境改账号,只需要改配置文件,脚本不用动。虽然练手项目不用这么讲究,但养成这个习惯,后面做项目会很受益。读取配置的代码不复杂,但能让脚本干净不少,也方便同事接手。

4.2 登录脚本实现:定位、输入、点击

写登录脚本主要分三步:打开登录页、填账号密码、点登录按钮。TPshop首页右上角有“登录”链接,可以先通过LINK_TEXT定位,也可以直接访问登录URL。进入登录页后,找到用户名输入框和密码输入框,填入数据,再点登录。用代码实现大概是:

driver.get("http://localhost/tpshop/index.php/Home/User/login.html") driver.find_element(By.NAME, "username").send_keys("13800138001") driver.find_element(By.NAME, "password").send_keys("123456") driver.find_element(By.CLASS_NAME, "login_btn").click() userinfo = WebDriverWait(driver, 10).until( EC.visibility_of_element_located((By.CLASS_NAME, "userinfo")) ) assert "13800138001" in userinfo.text

这里有个细节:登录页的用户名输入框在TPshop里的name有时是username,有时是mobile,两种都有可能出现。稳妥做法是先在浏览器里手动看元素结构,再写代码。另外,登录按钮的class名可能不止一个,比如login_btn btnCLASS_NAME不能带空格,要取其中一个看起来唯一的类名,或者用By.CSS_SELECTOR。很多人卡在这里,报错说找不到元素,其实不是没这个元素,而是class名没写对。

4.3 等待策略:不要一上来就sleep

新手写自动化最爱用time.sleep(3),页面加载慢就改成sleep(5),看着能跑,但脚本越来越慢,还特别容易偶发失败。正确做法是优先用显式等待。隐式等待driver.implicitly_wait(10)是全局的,轮询查找元素直到超时;显式等待WebDriverWait更精确,可以指定等待某个条件,比如按钮可点击、元素可见。

我建议全局设一个隐式等待兜底,关键操作再用显式等待精确控制。比如点击登录按钮前,等按钮可点击:

login_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CLASS_NAME, "login_btn")) ) login_btn.click()

这样等的是“按钮真的可以点”,而不是“傻等3秒再点”,稳定性会高很多。TPshop首页有些区域是异步加载的,如果明明定位到了却一直报element click intercepted,大概率是元素被遮住或者还没变成可点击状态,这时候就要注意等待条件了。还有一点,等待时间不要设置太长,一般10秒足够,太长会在页面卡死时浪费很多时间。

5. 常见问题与排查技巧实录

5.1 ChromeDriver版本不匹配,报错说了什么

最常见的报错是:

selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version x.y.z

这个报错已经告诉你了:驱动和浏览器版本不匹配。解决办法就是按前面说的,打开chrome://version看浏览器版本号,然后去下载对应版本的ChromeDriver,别图省事随便装一个。版本号主版本一致基本就行,比如浏览器是120,驱动也选120.x,不用纠结小版本完全一致。

补充一个很多人不知道的知识点:ChromeDriver不向后兼容老的Chrome。比如Chrome是109,你装一个114的ChromeDriver,即使报错信息没明说,也会导致Chrome无法启动或者崩溃。反过来,如果你在win7上用Chrome109,就只能用ChromeDriver109及对应的旧版本,新驱动在win7上可能直接无法运行。所以,环境问题优先从版本匹配上排查,不要一上来就怀疑代码写错了。

5.2 元素定位不到、提示NoSuchElementException怎么办

跑脚本最难受的就是找不到元素。报错NoSuchElementException后,先不要急着改定位表达式,按下面几步排查:第一,页面是否真的打开了?用driver.current_urldriver.title确认;第二,元素是否在iframe里?如果在,需要先driver.switch_to.frame()切进去;第三,页面是否还没加载完?改用显式等待;第四,元素是不是动态ID?比如TPshop有些按钮的id带了时间戳,这种就不能用id定位,要用name或xpath的相对定位。

还有一个比较隐蔽的问题:页面上存在多个相同class的元素,find_element默认返回第一个,可能不是你想要的。比如TPshop登录页和注册页都有“登录”按钮,如果你登录页定位用By.CLASS_NAME抓到了隐藏的注册页按钮,点击就会失败。这时候要给定位加一层缩小范围的前缀,比如:

driver.find_element(By.XPATH, "//div[@class='login_box']//input[@name='password']")

这样先限定到登录区域,再去找密码框,能排除不少干扰。如果还找不到,就把页面结构截图或打印出来,用driver.page_source看看有没有你想要的元素,很多时候是页面上根本没有这个字段,或者字段是后加载出来的,需要加等待。

5.3 提升脚本稳定性的几个习惯

最后分享几个我在实战中养成的小习惯。第一,每个关键步骤前加一行日志,比如print("开始输入用户名..."),脚本挂了能快速定位到哪一步;第二,失败时截图保存,给driver.get_screenshot_as_file("fail.png")包一层异常处理,排查时比看报错更直观;第三,公共方法尽量封装,比如input_text(locator, text)click_element(locator),别在一个用例里把所有find_element直接铺开;第四,定位表达式尽量用相对路径,能承受页面局部变化。

我自己在写TPshop这套练习时,最开始也是各种踩坑,光是driver版本就换了好几次,后来把环境固定成一套才稳定下来。有个排查了半天的案例是登录后断言一直失败,最后发现页面上有头像和用户名两个相同class的元素,取文本时取到了头像的alt属性。这种问题光看报错根本看不出来,一定要把日志和截图结合起来看。跑自动化就是这样,同一个坑踩过一次,下次就知道怎么躲了,这也是练习最大的价值。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 14:06:21

昇腾ATLAS 300V部署YOLO实战:从环境搭建到模型转换全流程

1. ATLAS 300V 24G到底是不是运算加速卡&#xff1a;先把定位搞清楚最近后台收到不少类似的问题&#xff0c;翻来覆去核心就是两个&#xff1a;ATLAS 300V 24G到底算不算运算加速卡&#xff0c;以及怎么在上面把YOLO跑起来。这两个问题其实是一个问题的两面——你只有先搞清楚这…

作者头像 李华
网站建设 2026/9/20 14:04:23

2026前端AI编程工具对比测评:React与Vue场景选型指南

1. 前端开发选AI编程工具&#xff0c;2026年这份对比测评报告帮你做决策前端圈子这两年最明显的变化&#xff0c;不是又出了什么新框架&#xff0c;而是写代码的方式正在被AI编程工具重新塑造。我身边不少做React和Vue的朋友&#xff0c;从最初把AI当“高级自动补全”&#xff…

作者头像 李华
网站建设 2026/9/20 14:01:36

Hugging Face:Qwen3 开源权重接到 TaoToken 供自建服务调用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华