Page Object模式是一种在自动化测试(尤其是针对Web应用程序的自动化测试)中广泛使用的设计模式。它的主要目的是将页面的元素定位和操作逻辑与测试用例进行分离,使得测试代码更加清晰、可维护和可复用。
在传统的自动化测试代码中,元素定位和对元素的操作通常直接混合在测试用例中。当页面结构发生变化时,比如元素的属性(如id、class等)改变或者元素的布局调整,就需要在多个测试用例中去逐一修改相关的元素定位和操作代码,这会导致代码的维护成本很高。
而Page Object模式通过将每个页面抽象成一个独立的类(即Page Object类),在这个类中封装了该页面所有相关元素的定位方法以及针对这些元素的操作方法。这样,当页面发生变化时,只需要在对应的Page Object类中修改相关代码即可,而不需要在众多的测试用例中去查找和修改,大大提高了代码的可维护性。
我以一个简单的Web登录页面为例,展示如何使用Page Object模式进行自动化测试(使用Selenium库进行Web自动化操作)。
Selenium环境安装
:首先,需要安装Selenium库(如果还未安装):
pip install selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
class LoginPage:
def __init__(self, driver):
self.driver = driver
# 定位用户名输入框
def locate_username_input(self):
return self.driver.find_element(By.ID, "username")
# 定位密码输入框
def locate_password_input(self):
return self.driver.find_element(By.ID, "password")
# 定位登录按钮
def locate_login_button(self):
return self.driver.find_element(By.ID, "login-button")
# 输入用户名
def enter_username(self, username):
username_input = self.locate_username_input()
username_input.clear()
username_input.send_keys(username)
# 输入密码
def enter_password(self, password):
password_input = self.locate_password_input()
password_input.clear()
password_input.send_keys(password)
# 点击登录按钮
def click_login_button(self):
login_button = self.locate_login_button()
login_button.click()
在上述LoginPage
类中:
__init__
方法接受一个浏览器驱动实例(如Chrome驱动实例),并将其保存为类的属性,以便在后续方法中使用该驱动来定位和操作页面元素。class TestLogin:
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("http://example.com/login")
self.login_page = LoginPage(self.driver)
def tearDown(self):
self.driver.quit()
def test_successful_login(self):
self.login_page.enter_username("test_user")
self.login_page.enter_password("test_password")
self.login_page.click_login_button()
# 这里可以添加更多的断言来验证登录是否成功,比如检查是否跳转到了预期页面等
在上述TestLogin
类中:
setUp
方法在每个测试方法执行之前被调用,它主要负责创建浏览器驱动实例,打开登录页面,并实例化LoginPage
类,以便在后续测试方法中可以使用LoginPage
类中的方法来操作登录页面。tearDown
方法在每个测试方法执行之后被调用,它负责关闭浏览器驱动实例。test_successful_login
是一个具体的测试方法,它通过调用LoginPage
类中的方法来完成输入用户名、输入密码和点击登录按钮的操作,之后还可以根据需要添加断言来验证登录是否成功(例如,检查是否跳转到了预期的页面等)。通过这样的方式,将登录页面的元素定位和操作封装在LoginPage
类中,而测试用例则专注于业务逻辑的验证,当登录页面的结构发生变化时,只需要在LoginPage
类中修改相关元素定位和操作的代码即可,不会影响到测试用例的逻辑。这就是Page Object模式在Python自动化测试中的基本应用方式。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
class LoginPage:
def __init__(self, driver):
self.driver = driver
def locate_username_input(self):
return self.driver.find_element(By.ID, "username")
def locate_password_input(self):
return self.driver.find_element(By.ID, "password")
def locate_login_button(self):
return self.driver.find_element(By.ID, "login-button")
def enter_username(self, username):
username_input = self.locate_username_input()
username_input.clear()
username_input.send_keys(username)
def enter_password(self, password):
password_input = self.locate_password_input()
password_input.clear()
password_input.send_keys(password)
def click_login_button(self):
login_button = self.locate_login_button()
login_button.click()
class SearchPage:
def __init__(self, driver):
self.driver = driver
def locate_search_box(self):
return self.driver.find_element(By.ID, "search-box")
def enter_search_term(self, term):
search_box = self.locate_search_box()
search_box.clear()
search_box.send_keys(term)
def click_search_button(self):
search_button = self.driver.find_element(By.ID, "search-button")
search_button.click()
def get_search_results(self):
wait = WebDriverWait(self.driver, 10)
results = wait.until(EC.presenceOfAllElementsLocatedBy(By.CLASS_NAME, "product-item"))
return results
class TestEcommerce:
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://www.example-ecommerce.com")
def tearDown(self):
self.driver.quit()
def test_login_and_search(self):
login_page = LoginPage(self.driver)
search_page = SearchPage(self.driver)
login_page.enter_username("test_user")
login_page.enter_password("test_password")
login_page.click_login_button()
time.sleep(2) # 等待登录完成,可根据实际情况调整
search_page.enter_search_term("laptop")
search_page.click_search_button()
results = search_page.get_search_results()
assert len(results) > 0, "No search results found."
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class SocialMediaLoginPage:
def __init__(self, driver):
self.driver = driver
def locate_email_input(self):
return self.driver.find_element(By.ID, "email")
def locate_password_input(self):
return self.driver.find_element(By.ID, "password")
def locate_login_button(self):
return self.driver.find_element(By.ID, "login-button")
def enter_email(self, email):
email_input = self.locate_email_input()
email_input.clear()
email_input.send_keys(email)
def enter_password(self, password):
password_input = self.locate_password_input()
password_input.clear()
password_input.send_keys(password)
def click_login_button(self):
login_button = self.locate_login_button()
login_button.click()
class SocialMediaPostPage:
def __init__(self, driver):
self.driver = driver
def locate_post_textarea(self):
return self.driver.find_element(By.ID, "post-textarea")
def enter_post_content(self, content):
post_textarea = self.locate_post_textarea()
post_textarea.clear()
post_textarea.send_keys(content)
def click_post_button(self):
post_button = self.driver.find_element(By.ID, "post-button")
post_button.click()
def get_post_status(self):
wait = WebDriverWait(self.driver, 10)
status = wait.until(EC.visibilityOfElementLocated(By.ID, "post-status"))
return status.text
class TestSocialMedia:
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://www.example-socialmedia.com")
def tearDown(self):
self.driver.quit()
def test_login_and_post(self):
login_page = SocialMediaLoginPage(self.driver)
post_page = SocialMediaPostPage(self.driver)
login_page.enter_email("test_email@example.com")
login_page.enter_password("test_password")
login_page.click_login_button()
post_page.enter_post_content("This is a test post.")
post_page.click_post_button()
status = post_page.get_post_status()
assert "Posted successfully" in status, "Post was not successful."
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class TravelBookingLoginPage:
def __init__(self, driver):
self.driver = driver
def locate_username_input(self):
return self.driver.find_element(By.ID, "username")
def locate_password_input(self):
return self.driver.find_element(By.ID, "password")
def locate_login_button(self):
return self.driver.find_element(By.ID, "login-button")
def enter_username(self, username):
username_input = self.locate_username_input()
username_input.clear()
username_input.send_keys(username)
def enter_password(self, password):
password_input = self.locus_password_input()
password_input.clear()
password_input.send_keys(password)
def click_login_button(self):
login_button = self.locate_login_button()
login_button.click()
class TravelBookingHotelPage:
def __init__(self, driver):
self.driver = driver
def locate_destination_input(self):
return self.driver.find_element(By.ID, "destination")
def enter_destination(self, destination):
destination_input = self.locate_destination_input()
destination_input.clear()
destination_input.send_keys(destination)
def locate_check_in_date_input(self):
return self.driver.find_element(By.ID, "check-in-date")
def enter_check_in_date(self, date):
check_in_date_input = self.locate_check_in_date_input()
check_in_date_input.clear()
check_in_date_input.send_keys(date)
def locate_check_out_date_input(self):
return self.driver.find_element(By.ID, "check-out-date")
def enter_check_out_date(self, date):
check_out_date_input = self.locate_check_out_date_input()
check_out_date_input.clear()
check_out_date_input.send_keys(date)
def locate_search_button(self):
return self.driver.find_element(By.ID, "search-button")
def click_search_button(self):
search_button = self.locate_search_button()
search_button.click()
def get_hotel_results(self):
wait = WebDriverWait(self.driver, 10)
results = wait.until(EC.presenceOfAllElementsLocatedBy(By.CLASS_NAME, "hotel-item"))
return results
class TestTravelBooking:
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("https://www.example-travelbooking.com")
def tearDown(self):
self.driver.quit()
def test_login_and_book_hotel():
login_page = TravelBookingLoginPage(self.driver)
hotel_page = TravelBookingHotelPage(self.driver)
login_page.enter_username("test_user")
login_page.enter_password("test_password")
login_page.click_login_button()
hotel_page.enter_destination("New York")
hotel_page.enter_check_in_date("2024-12-01")
hotel_page.enter_check_out_date("2024-12-05")
hotel_page.click_search_button()
results = hotel_page.get_hotel_results()
assert len(results) > 0, "No hotel results found."
这些代码示例展示了如何在不同类型的Web应用场景下应用Page Object模式,通过将页面元素定位和操作封装在各自的Page Object类
中,使得测试用例更加清晰、可维护和可复用。