Page Object Model(页面对象模型)是一种设计模式,将页面元素和操作封装成对象,使测试代码和页面元素的定位及操作分离,提高了测试代码的可维护性和可复用性。在典型的 POM 实现中,通常包含四层对象:基础页面对象、具体页面对象、测试用例对象和测试数据对象。
project/
│
├── pages/ # 页面对象模块
│ ├── base_page.py # 基础页面对象
│ ├── login_page.py # 登录页面对象
│
├── tests/ # 测试用例模块
│ ├── test_login.py # 登录测试用例
│
├── utils/ # 工具模块
│ ├── data_utils.py # 测试数据对象
│
├── config/ # 配置模块
│ ├── config.ini # 配置文件
│
├── run_tests.py # 测试运行文件
pages/base_page.py
)from 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 find_element(self, by, value, timeout=10):
return WebDriverWait(self.driver, timeout).until(
EC.presence_of_element_located((by, value))
)
def click(self, by, value):
element = self.find_element(by, value)
element.click()
def send_keys(self, by, value, text):
element = self.find_element(by, value)
element.send_keys(text)
pages/login_page.py
)from pages.base_page import BasePage
from selenium.webdriver.common.by import By
class LoginPage(BasePage):
USERNAME_INPUT = (By.ID, 'username')
PASSWORD_INPUT = (By.ID, 'password')
LOGIN_BUTTON = (By.ID, 'login-button')
def __init__(self, driver):
super().__init__(driver)
def enter_username(self, username):
self.send_keys(*self.USERNAME_INPUT, username)
def enter_password(self, password):
self.send_keys(*self.PASSWORD_INPUT, password)
def click_login_button(self):
self.click(*self.LOGIN_BUTTON)
def login(self, username, password):
self.enter_username(username)
self.enter_password(password)
self.click_login_button()
tests/test_login.py
)import unittest
from selenium import webdriver
from pages.login_page import LoginPage
from utils.data_utils import get_test_data
class TestLogin(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get('https://example.com/login')
self.login_page = LoginPage(self.driver)
def test_successful_login(self):
username, password = get_test_data()
self.login_page.login(username, password)
# 这里可以添加断言来验证登录是否成功
# 例如:self.assertEqual(self.driver.current_url, 'https://example.com/dashboard')
def tearDown(self):
self.driver.quit()
if __name__ == '__main__':
unittest.main()
utils/data_utils.py
)def get_test_data():
# 这里可以从配置文件、数据库等获取测试数据
username = 'testuser'
password = 'testpassword'
return username, password
run_tests.py
)import unittest
if __name__ == "__main__":
suite = unittest.TestLoader().loadTestsFromTestCase(TestLogin)
unittest.TextTestRunner(verbosity=2).run(suite)
BasePage
):封装了一些通用的操作方法,如查找元素、点击元素和输入文本等,为具体页面对象提供了基础功能。LoginPage
):继承自 BasePage
,定义了登录页面的元素定位器和操作方法,将登录页面的元素和操作封装在一起。TestLogin
):使用 unittest
框架编写测试用例,创建 LoginPage
对象并调用其方法进行登录操作,最后添加断言来验证登录结果。get_test_data
):负责提供测试所需的数据,这里简单地返回了一个用户名和密码,实际应用中可以从配置文件、数据库等获取数据。通过这种四层对象的设计,测试代码和页面元素的定位及操作分离,提高了代码的可维护性和可复用性。当页面元素发生变化时,只需要修改具体页面对象中的元素定位器和操作方法,而不需要修改测试用例代码。
策略模式是一种行为设计模式,它定义了一系列的算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户端。在自动化测试的数据获取场景中,我们可以使用策略模式来根据不同的数据源类型(数据库、CSV 文件、Excel 文件)获取测试数据。
data_fetching_strategy/
│
├── data_fetch_strategy.py # 策略接口和具体策略类
├── data_fetcher.py # 上下文类
├── db_config.py # 数据库配置文件
├── main.py # 主程序
├── sample.csv # 示例 CSV 文件
├── sample.xlsx # 示例 Excel 文件
db_config.py
)# 假设使用 SQLite 数据库
DB_CONFIG = {
'database': 'example.db'
}
data_fetch_strategy.py
)import sqlite3
import csv
import pandas as pd
# 策略接口
class DataFetchStrategy:
def fetch_data(self):
pass
# 从数据库获取数据的策略类
class DatabaseFetchStrategy(DataFetchStrategy):
def __init__(self, db_config):
self.db_config = db_config
def fetch_data(self):
conn = sqlite3.connect(self.db_config['database'])
cursor = conn.cursor()
cursor.execute('SELECT * FROM your_table')
data = cursor.fetchall()
conn.close()
return data
# 从 CSV 文件获取数据的策略类
class CSVFetchStrategy(DataFetchStrategy):
def __init__(self, file_path):
self.file_path = file_path
def fetch_data(self):
data = []
with open(self.file_path, 'r', newline='') as csvfile:
reader = csv.reader(csvfile)
for row in reader:
data.append(row)
return data
# 从 Excel 文件获取数据的策略类
class ExcelFetchStrategy(DataFetchStrategy):
def __init__(self, file_path):
self.file_path = file_path
def fetch_data(self):
df = pd.read_excel(self.file_path)
return df.values.tolist()
data_fetcher.py
)from data_fetch_strategy import DataFetchStrategy, DatabaseFetchStrategy, CSVFetchStrategy, ExcelFetchStrategy
from db_config import DB_CONFIG
class DataFetcher:
def __init__(self, source_type):
self.source_type = source_type
self.strategy = self._get_strategy()
def _get_strategy(self):
if self.source_type == 'DB':
return DatabaseFetchStrategy(DB_CONFIG)
elif self.source_type == 'CSV':
return CSVFetchStrategy('sample.csv')
elif self.source_type == 'Excel':
return ExcelFetchStrategy('sample.xlsx')
else:
raise ValueError(f"Unsupported source type: {self.source_type}")
def fetch_data(self):
return self.strategy.fetch_data()
main.py
)from data_fetcher import DataFetcher
def main():
# 从数据库获取数据
db_fetcher = DataFetcher('DB')
db_data = db_fetcher.fetch_data()
print("从数据库获取的数据:")
for row in db_data:
print(row)
# 从 CSV 文件获取数据
csv_fetcher = DataFetcher('CSV')
csv_data = csv_fetcher.fetch_data()
print("\n从 CSV 文件获取的数据:")
for row in csv_data:
print(row)
# 从 Excel 文件获取数据
excel_fetcher = DataFetcher('Excel')
excel_data = excel_fetcher.fetch_data()
print("\n从 Excel 文件获取的数据:")
for row in excel_data:
print(row)
if __name__ == "__main__":
main()
DataFetchStrategy
)定义了一个抽象方法 fetch_data
,所有具体的策略类都需要实现这个方法,用于获取数据。
DatabaseFetchStrategy
:实现了从数据库中获取数据的逻辑。使用 sqlite3
连接到数据库,执行 SQL 查询语句获取数据,并在操作完成后关闭数据库连接。CSVFetchStrategy
:实现了从 CSV 文件中获取数据的逻辑。使用 Python 的内置 csv
模块读取 CSV 文件内容,并将每行数据添加到列表中返回。ExcelFetchStrategy
:实现了从 Excel 文件中获取数据的逻辑。使用 pandas
库读取 Excel 文件,将数据转换为列表形式返回。DataFetcher
)source_type
参数选择相应的策略类。_get_strategy
方法根据 source_type
决定返回哪种具体的策略对象。fetch_data
方法调用当前策略对象的 fetch_data
方法来获取数据。main.py
)创建不同 source_type
的 DataFetcher
对象,调用其 fetch_data
方法获取数据并打印输出。
db_config.py
和 DatabaseFetchStrategy
类中的数据库连接和操作代码。pandas
库,可以使用 pip install pandas
进行安装。your_table
需要替换为实际的数据库表名,sample.csv
和 sample.xlsx
需要替换为实际的文件路径。通过使用策略模式,我们可以方便地根据不同的数据源类型切换数据获取方式,提高了代码的可维护性和可扩展性。在自动化测试中,可将该数据获取策略与 POM 模式结合,为测试用例提供多样化的测试数据。例如,可在 utils/data_utils.py
的 get_test_data
方法中调用 DataFetcher
来根据配置选择合适的数据源获取测试数据,进一步增强测试的灵活性和可配置性。