ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Web自动化测试11-实验案例1-1:百度搜索搭建PO框架

2026/9/26 11:16:30 拓冰建站 浏览量
Web自动化测试11-实验案例1-1:百度搜索搭建PO框架 实验目标打开百度、定位搜索框、输入关键词、点搜索。实验目的理解PO框架实现框架搭建第一步实现功能的脚本版代码from selenium import webdriver from selenium.webdriver.common.by import By url https://www.baidu.com driver webdriver.Edge() driver.get(url) driver.find_element(By.ID,chat-textarea).send_keys(软件测试) driver.find_element(By.ID,chat-submit-button).click() driver.quit()值得注意的是页面类文件里不能保留脚本代码。当前版本在模块顶层直接写了driver webdriver.Edge()以及两行find_element调用——如果该文件被导入一执行 import 就会弹出浏览器并自动跑一遍搜索。模块顶层的代码会在导入那一刻立即执行这正是「脚本」与「模块」的本质区别能被 import 的文件只应定义内容不应主动执行操作真正执行任务的入口应放在run_baidu.py中。所以我们需要先简单地把这个脚本代码分成页面代码和运行代码两部分第二步将脚本代码拆分成页面代码和运行代码页面代码baidu_page.py# 打开百度、定位搜索框、输入关键词、点搜索。 from selenium.webdriver.common.by import By class BaiduPage: URL https://www.baidu.com SEARCH_INPUT (By.ID,chat-textarea) SEARCH_BUTTON (By.ID,chat-submit-button) #构造方法对driver值进行初始化 #由于只负责初始化所以不能return值 #为后面BasePage铺路 def __init__(self, driver): self.driver driver def open(self): self.driver.get(self.URL) return self def search(self,keyword): # river.find_element(By.ID,chat-textarea).send_keys(软件测试) self.driver.find_element(*self.SEARCH_INPUT).send_keys(keyword) # driver.find_element(By.ID,chat-submit-button).click() self.driver.find_element(*self.SEARCH_BUTTON).click() return self运行代码run_baidu.pyfrom selenium import webdriver #导入在baidu_page页面定义的BaiduPage类 from pages.baidu_page import BaiduPage driver webdriver.Edge() #调用方法打开网页查找软件测试 BaiduPage(driver).open().search(软件测试) #输出当前标签页标题用于粗略检测是否标题改变搜索有没有生效 print(driver.title) #关闭浏览器 driver.quit()第三步抽 BasePageBase层代码在项目中涉及底层操作如对click、send_keys等事件的封装用于提高代码的重用性。操作方法把open()、search()中那两行重复的self.driver.find_element(...)提取到基类里封装成一个find(locator)方法再让BaiduPage继承它。抽取之后BaiduPage只需保留定位符和自身的业务方法——这正是 PO 模式的核心价值所在。好处消重。项目一会有BaiduPage、LoginPage、SearchResultPage……每个页面至少有 find / click / input 三种动作。不抽就是每个方法里重复self.driver.find_element(...)抽了页面类里每个动作只剩一行self.click(self.SEARCH_BUTTON)。改一处全项目生效。这才是真正的价值。比如后面你发现「元素等待要改成 15 秒」或者想加「找不到元素时自动截图」def find(self, locator): try: return WebDriverWait(self.driver, 15).until( EC.visibility_of_element_located(locator)) except TimeoutException: self.driver.save_screenshot(error.png) # 全项目自动有失败截图 raise改完这一处BaiduPage、LoginPage、以后所有页面全部获得截图能力一行用例都不用动。不抽的话你得改十个文件。隔离技术细节。Selenium 的写法变了、等待策略要换、换成 Playwright——动的只有BasePage页面类里的业务方法原样不变。Base层代码 base_page.pyfrom selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class BasePage: def __init__(self, driver): self.driver driver def open(self, url): self.driver.get(url) return self def find(self, locator): #显示等待元素可见再返回等待能力就此对所有页面生效 return WebDriverWait(self.driver, 10).until( EC.visibility_of_element_located(locator) ) def click(self, locator): self.find(locator).click() return self def input_text(self, locator, text): self.find(locator).send_keys(text) return self页面代码baidu_page.py在后期调试过程中发现由于百度有反爬安全机制在跳转过程中会遇到安全检验需要人为通过。所以在search()中添加了一个强制等待40秒的操作用于人手动通过安全人机测试# 打开百度、定位搜索框、输入关键词、点搜索。 from selenium.webdriver.common.by import By #导入写好的BasePage from pages.base_page import BasePage class BaiduPage(BasePage): URL https://www.baidu.com SEARCH_INPUT (By.ID,chat-textarea) SEARCH_BUTTON (By.ID,chat-submit-button) # #构造方法对driver值进行初始化 # #由于只负责初始化所以不能return值 # #为后面BasePage铺路 # def __init__(self, driver): # self.driver driver def open(self): # self.driver.get(self.URL) # return self return super().open(self.URL) def search(self,keyword): # # river.find_element(By.ID,chat-textarea).send_keys(软件测试) # self.driver.find_element(*self.SEARCH_INPUT).send_keys(keyword) self.input_text(self.SEARCH_INPUT,keyword) # # driver.find_element(By.ID,chat-submit-button).click() # self.driver.find_element(*self.SEARCH_BUTTON).click() self.click(self.SEARCH_BUTTON) # 强制等待 40 秒手动过验证码 import time time.sleep(40) return self第四步搭建测试testcasesconftest.py代码conftest让 pytest 在运行测试时自动加载里面的配置和公共代码不用再手动导入。比如pytest 会自动把conftest.py所在的目录加入sys.path这样from pages.xxx import xxx就能找到了。# conftest.py —— 放在项目根目录pytest 启动时会自动加载不需要任何地方 import 它 import pytest from selenium import webdriver pytest.fixture # 声明这是 fixture用例只要写上同名参数就能拿到 def driver(): # 函数名 driver 就是 fixture 的名字 d webdriver.Edge() # 前置启动浏览器 yield d # 交给用例去用用例跑完代码从这一行之后继续 d.quit() # 后置用例通过也好、失败也好都会执行关闭test_baidu.py代码# testcases/test_baidu.py —— 文件名必须以 test_ 开头pytest 才会收集 from pages.baidu_page import BaiduPage # 导入页面类 def test_baidu_search(driver): # 函数名也要 test_ 开头参数 driver 对应conftest那个 fixture BaiduPage(driver).open().search(软件测试) # 只写做什么不关心怎么定位 assert 软件测试 in driver.title # 判断结果不满足就报 FAILED总结项目目录baidu_page/ ├── conftest.py ├── run_baidu.py ← 保留当调试入口 ├── pages/ │ ├── base_page.py │ └── baidu_page.py └── testcases/ └── test_baidu.py四层就清楚了BasePage管动作、BaiduPage管业务、conftest.py管环境、testcases管判断。