自动化测试神器PageObject代码减少50%维护成本降70%01 自动化测试的噩梦改一个元素全局崩溃“登录页面改了个按钮ID跑了3年的脚本全挂了。”这是某测试团队的真实故事。一个小改动200测试用例全部失败修了整整2天。问题的根源在于测试代码和页面元素绑定了。而PageObject模式就是来解决这个问题的。02 什么是PageObject一句话解释PageObject 把页面当对象封装。每个页面对应一个类页面上的元素是这个类的属性操作是这个类的方法。# ❌ 传统写法元素和操作混在一起deftest_login():driver.find_element(By.ID,username).send_keys(admin)driver.find_element(By.ID,password).send_keys(123456)driver.find_element(By.ID,login-btn).click()assert首页indriver.title# ✅ PageObject写法元素封装进页面类classLoginPage:def__init__(self,driver):self.driverdriverdefinput_username(self,username):self.driver.find_element(By.ID,username).send_keys(username)definput_password(self,password):self.driver.find_element(By.ID,password).send_keys(password)defclick_login(self):self.driver.find_element(By.ID,login-btn).click()deflogin(self,username,password):self.input_username(username)self.input_password(password)self.click_login()# 测试用例简洁到极致deftest_login():LoginPage(driver).login(admin,123456)assert首页indriver.title03 3层架构让测试代码像乐高一样拼第1层页面对象层PageObjects每个页面一个类只管元素定位和方法封装。classLoginPage:def__init__(self,driver):self.driverdriverpropertydefusername_input(self):returnself.driver.find_element(By.ID,username)propertydeflogin_button(self):returnself.driver.find_element(By.ID,login-btn)deflogin(self,username,password):self.username_input.send_keys(username)self.driver.find_element(By.ID,password).send_keys(password)self.login_button.click()第2层业务逻辑层TestSteps封装业务流程一个方法完成一系列操作。classLoginSteps:def__init__(self,driver):self.login_pageLoginPage(driver)deflogin_with_valid_user(self):self.login_page.login(admin,password123)# 等待跳转time.sleep(2)returnHomePage(self.driver)deflogin_with_invalid_user(self):self.login_page.login(admin,wrongpassword)returnself.login_page.get_error_message()第3层测试用例层TestCases只写做什么不写怎么做。deftest_login_success():stepsLoginSteps(driver)home_pagesteps.login_with_valid_user()asserthome_page.get_title()首页deftest_login_failure():stepsLoginSteps(driver)error_msgsteps.login_with_invalid_user()assert用户名或密码错误inerror_msg04 真实项目实战电商后台登录项目结构tests/ ├── pages/ │ ├── __init__.py │ ├── login_page.py │ ├── home_page.py │ └── admin_page.py ├── steps/ │ ├── __init__.py │ └── login_steps.py ├── cases/ │ ├── __init__.py │ └── test_login.py └── conftest.pylogin_page.py完整代码fromselenium.webdriver.common.byimportByfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasECclassLoginPage:# 元素定位器USERNAME_INPUT(By.ID,username)PASSWORD_INPUT(By.ID,password)LOGIN_BUTTON(By.ID,login-btn)ERROR_MSG(By.CLASS_NAME,error-message)REMEMBER_CHECKBOX(By.ID,remember-me)def__init__(self,driver):self.driverdriver self.waitWebDriverWait(driver,10)definput_username(self,username):self.wait.until(EC.presence_of_element_located(self.USERNAME_INPUT))self.driver.find_element(*self.USERNAME_INPUT).clear()self.driver.find_element(*self.USERNAME_INPUT).send_keys(username)definput_password(self,password):self.driver.find_element(*self.PASSWORD_INPUT).clear()self.driver.find_element(*self.PASSWORD_INPUT).send_keys(password)defcheck_remember_me(self):checkboxself.driver.find_element(*self.REMEMBER_CHECKBOX)ifnotcheckbox.is_selected():checkbox.click()defclick_login(self):self.driver.find_element(*self.LOGIN_BUTTON).click()deflogin(self,username,password,rememberFalse):self.input_username(username)self.input_password(password)ifremember:self.check_remember_me()self.click_login()defget_error_message(self):returnself.wait.until(EC.presence_of_element_located(self.ERROR_MSG)).text05 为什么要用PageObject数据说话指标传统写法PageObject元素变更影响范围200用例1个文件代码重复率60%10%维护时间/周8小时2小时新人上手成本3天1天一句话总结PageObject不是必须但它是让自动化测试活下来的唯一出路。知识星球软件测试成长圈