做自动化测试的人大多都遇到过这种情况:改了一个登录流程,结果几十个用例全挂了;或者换个浏览器,整个脚本跑不起来。问题往往不是出在代码写得差,而是结构没搭好。就像盖房子,地基和框架没理清楚,装修再漂亮也扛不住风雨。
为什么需要分层?
想象你家的厨房。如果所有东西——锅碗瓢盆、调料、食材——全堆在一个抽屉里,每次做饭都得翻半天。测试自动化也一样。把所有逻辑塞进一个脚本里,短期能跑通,长期维护成本极高。
分层的核心思想是“各司其职”。把不同职责的代码拆开,比如操作页面的归一类,写断言的归一类,准备数据的另放一边。这样改登录逻辑时,只动对应的一层,不影响其他用例。
常见的三层结构
最实用的分法是三层:基础操作层、业务封装层、用例层。
基础操作层负责和工具打交道。比如点击、输入、等待这些动作,统一封装成方法。以后换 Selenium 到 Playwright,只需要改这一层,上层几乎不用动。
def click_element(driver, locator):
element = driver.find_element(*locator)
element.click()
def input_text(driver, locator, text):
element = driver.find_element(*locator)
element.clear()
element.send_keys(text)
业务封装层对应具体功能。比如“用户登录”这件事,不管在哪个用例里出现,都调这个方法。参数可以是用户名密码,内部处理跳转、填表、提交。
class LoginPage:
def __init__(self, driver):
self.driver = driver
def login(self, username, password):
input_text(self.driver, ("id", "username"), username)
input_text(self.driver, ("id", "password"), password)
click_element(self.driver, ("id", "login-btn"))
用例层就干净多了。只关心“我要测什么”,不关心“怎么点”“怎么输”。读起来像自然语言,新来的同事也能看懂。
def test_user_login_success():
driver = webdriver.Chrome()
login_page = LoginPage(driver)
login_page.login("testuser", "123456")
assert "dashboard" in driver.current_url
driver.quit()
数据与配置分离
别把测试数据写死在代码里。用户名密码、URL、超时时间这些,统统放到配置文件或环境变量中。本地调试用一套地址,上线前切换到预发环境,改配置就行,不用碰代码。
比如建个 config.yaml:
base_url: https://staging.example.com
timeout: 10
users:
admin: "admin/abcd1234"
guest: "guest/987654"
这样换环境时,连 Jenkins 的构建参数改一下就能跑,不用重新打包代码。
实际场景中的好处
有个团队之前每个用例都自己写登录逻辑,后来项目加了验证码,光改登录就花了三天。后来改成分层,只改了 LoginPage 里的 login 方法,加了个图像识别跳过的逻辑,其他用例一行不动,当天就恢复了运行。
还有个例子,前端把“提交订单”按钮的 class 名从 btn-submit 改成 submit-btn,没分层的脚本全崩了。而用了元素定位集中管理的项目,只改了一个 locators.py 文件就解决了。
分层不是为了炫技,是为了让自动化真正可持续。脚本写一次,能用三个月和能用三年,背后的结构差别就在这儿。