pom web 自动化测试框架分享

这是初版的 pom web 测试框架,目录如下同时部分代码也放在下面,详细代码可前往 github 查看,欢迎大家给出宝贵意见。

python 复制代码
|--base
|    base_page.py(封装方法)
|
|--config
|    allure_config.py(测试报告配置)
|
|--data
|    code(验证码)
|    user.yaml(用户目录)
|
|--logs
|    log(日志文件)
|    log.py(日志模块)
|
|--page_object
|    login_page.py(登陆页面元素及流程)
|
|--reports(测试报告存放处)
|    allure-page
|    report
|
|--screenshot
|    err_screenhot(错误截图)
|    screenshot.py(截图模块)
|
|--test_case
|    conftest(fixture配置)
|    test_login.py(登录测试用例)
|
|--utils
|    util(公共方法,类似于验证码识别等)
|    web_driver.py(driver配置)
|
|--run.py(测试框架运行模块)

base(封装方法)

python 复制代码
class BasePage:
    def __init__(self, driver):
        self.driver = driver
        self.logger = Logs.get_logger()
        self.scr = Screenshot(driver)

    """打开url"""

    def open_url(self, url: str):
        self.driver.maximize_window()
        self.logger.info('最大化窗口')
        self.driver.get(url)
        self.logger.info(f'打开网址:{url}')
        # self.driver.implicitly_wait(80)

    """元素定位,元组形态,返回web_element对象"""

    def locator(self, loc: tuple) -> WebElement:
        try:
            # 显示等待直到元素可见并可交互
            return self.display_wait(loc)

        except NoSuchElementException:
            self.logger.error(f'元素{loc}未找到')
            self.scr.screenshot(loc)
            raise

        except TimeoutException:
            self.logger.error(f'元素{loc}未在规定时间内变为可见')
            self.scr.screenshot(loc)
            raise

config(测试报告配置)

python 复制代码
# 用户数据路径
user_data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data', 'user.yaml')


# 测试用例路径
def case_path(path):
    return os.path.join(os.path.dirname(path), 'test_cases')


# 测试报告路径
def report_path(path):
    return os.path.join(os.path.dirname(path), 'reports')


# 执行 pytest 命令生成 Allure 报告配置
pytest_command = [
    "pytest",
    "test_login.py", # 登陆测试
    "test_home.py", # 首页测试
    "test_search.py", # 搜索测试
    "--alluredir=../reports/report",
    "--clean-alluredir"]
# 执行 Allure 命令生成并打开报告配置
allure_command = ["allure", "generate", "report", "--clean"]
# 打开allure报告
allure_open = ["allure", "open", "allure-report"]

logs(日志)

python 复制代码
class Logs:
    LOG_DIRECTORY = os.path.join(os.path.dirname(__file__), 'log_file')
    LOG_FORMAT = '[%(asctime)s] %(levelname)s %(name)s(%(lineno)d): %(message)s'
    LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
    LOG_LEVEL = logging.INFO
    BACKUP_COUNT = 0
    _logger = None

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.ensure_log_directory()

    @classmethod
    def ensure_log_directory(cls):
        if not os.path.exists(cls.LOG_DIRECTORY):
            os.makedirs(cls.LOG_DIRECTORY)

    @classmethod
    def get_logger(cls):
        if cls._logger is None:
            try:
                cls.ensure_log_directory()
                log_path = os.path.join(cls.LOG_DIRECTORY, f'{time.strftime("%Y%m%d")}.log')

                file_handler = TimedRotatingFileHandler(log_path, when="midnight", interval=1,
                                                        encoding='utf8', backupCount=cls.BACKUP_COUNT)

                formatter = logging.Formatter(cls.LOG_FORMAT, datefmt=cls.LOG_DATE_FORMAT)
                file_handler.setFormatter(formatter)

                cls._logger = logging.getLogger(cls.__name__)
                cls._logger.setLevel(cls.LOG_LEVEL)
                cls._logger.addHandler(file_handler)  
            except Exception as e:
                raise RuntimeError(f"无法初始化类的记录器 '{cls.__name__}': {e}")

        return cls._logger

page_object(页面对象)

python 复制代码
class LoginPage(BasePage):
    # 网址
    _url = 'http://baidu.com'
    # 账号
    _account = ('id', 'account')
    # 密码
    _password = ('id', 'PASSWORD')
    # 登录
    _login_button = ('id', 'login_button')

    def correct_login(self, username, password):
        with allure.step("打开登陆页面"):
            self.open_url(self._url)
        with allure.step(f"输入账号:{username}"):
            self.input(self._account, username)
        with allure.step(f"输入密码:{password}"):
            self.input(self._password, password)
        with allure.step("点击登陆"):
            self.click(self._login_button)

screenshot(截图)

python 复制代码
class Screenshot:
    def __init__(self, driver):
        self._driver = driver
        self._screenshot_path = os.path.join(os.path.dirname(__file__), 'err_screenshot')
        self._ensure_screenshot_directory()
        self._logger = Logs.get_logger()
    def _ensure_screenshot_directory(self):
        try:
            if not os.path.exists(self._screenshot_path):
                os.makedirs(self._screenshot_path)
        except Exception as e:
            self._logger.error(f"创建屏幕截图目录时出错: {e}")
    def screenshot(self, error_name):
        date_time = datetime.now().strftime('%Y-%m-%d_%H.%M.%S')
        screenshot_name = f'{error_name}_{date_time}.png'
        screenshot_path = os.path.join(self._screenshot_path, screenshot_name)
        try:
            self._driver.get_screenshot_as_file(screenshot_path)
            with open(screenshot_path, 'rb') as image_file:
                image_data = image_file.read()
                allure.attach(image_data, name=screenshot_name, attachment_type=allure.attachment_type.PNG)
                self._logger.info(f"截图成功: {screenshot_path}")
        except FileNotFoundError as e:
            self._logger.error(f"保存截图时文件路径不存在: {e}")
        except Exception as e:
            self._logger.error(f"截取屏幕快照并保存时出错: {type(e).__name__}: {e}")

test_case(测试用例)

conftest

python 复制代码
@pytest.fixture(scope="class")
def driver():
    with allure.step("webdriver初始化"):
        driver_instance = init_driver()
    try:
        yield driver_instance
    finally:
        with allure.step("退出浏览器"):
            driver_instance.quit()

test_login.py

python 复制代码
@allure.epic("xxx系统")
@allure.feature("首页登陆页面")
class TestLogin:
    @pytest.fixture(autouse=True)
    def setup(self, driver):
        self._lp = LoginPage(driver)
    @allure.title("正确账号登录")
    @allure.description("验证正确账号可以登录首页")
    @allure.severity(allure.severity_level.BLOCKER)
    @pytest.mark.parametrize("login_account", yaml.safe_load(open(user_data_path))['login_data'])
    def test_login(self, driver, login_account):
        try:
            self._lp.correct_login(login_account['CorrectAccount'], login_account['CorrectPassword'])
        except Exception as e:
            screenshot_taker = Screenshot(driver)
            screenshot_taker.screenshot(f"登陆出错")
            raise e

unitls

unil

未用到公共方法,暂未配置

web_driver

python 复制代码
def init_driver():
    options = Options()
    # 可选配置项
    options.page_load_strategy = 'eager'  # 页面加载策略,默认为'normal',可选'eager'和'none'。
    # options.add_argument('--headless')  #无头模式
    options.add_argument('--disable-gpu')  # 禁用gpu
    options.add_argument('--user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, '
                         'like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0"')  # 用户代理
    # options.add_argument('--incognito')  # 隐身模式
    options.add_argument('--disable-infobars')  # 禁用信息栏(浏览器正在被自动化工具控制)
    options.add_argument('--start-maximized')  # 窗口最大化
    options.add_argument('--ignore-certificate-errors')  # 忽略证书错误
    options.add_argument('--no-sandbox')  # 禁用沙箱模式

    # 设置浏览器首选项
    prefs = {
        'download.prompt_for_download': False,  # 下载文件时是否提示保存对话框
        'safebrowsing.enabled': True,  # 是否启用安全浏览功能
        'credentials_enable_service': False,  # 是否启用保存密码提示
        'profile.password_manager_enabled': False  # 是否启用密码管理功能
    }
    options.add_experimental_option('prefs', prefs)

    driver = webdriver.Chrome(options=options)

    return driver

run(运行文件)

python 复制代码
# 初始化日志配置
logger = Logs.get_logger()

# 路径配置
BASE_DIR = os.path.dirname(__file__)
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_cases')
REPORT_DIR = os.path.join(BASE_DIR, 'reports')


def main():
    try:
        # 执行 pytest 命令生成 Allure 报告
        logger.info("正在运行 pytest 以生成 Allure 报告...")
        subprocess.run(pytest_command, cwd=TEST_CASE_DIR, shell=True)

        # 执行 Allure 命令生成报告
        logger.info("正在生成 Allure 报告...")
        subprocess.run(allure_command, cwd=REPORT_DIR, shell=True)

        # 打开 Allure 报告
        logger.info("打开Allure报告...")
        subprocess.run(allure_open, cwd=REPORT_DIR, shell=True)
    except subprocess.CalledProcessError as e:
        logger.error(f"发生错误: {e}")
        exit(1)


if __name__ == "__main__":
    main()
相关推荐
测试渣4 小时前
JIRA/Xray测试管理工具的最佳实践:从基础到高阶的全场景指南
测试工具·自动化·jira
测试老哥4 小时前
什么是集成测试?集成的方法有哪些?
自动化测试·软件测试·python·测试工具·职场和发展·单元测试·集成测试
Feng.Lee5 小时前
如何使用K8S快速部署测试环境
测试工具·云原生·容器·kubernetes·可用性测试
小小的测试一下12 小时前
业务流程先导及流程图回顾
功能测试·软件工程
春风又。13 小时前
接口自动化——初识pytest
python·测试工具·自动化·pytest
HaiFan.15 小时前
论坛系统的测试
功能测试
一个幽默的程序员15 小时前
如何快速备份你的 API 吗? Postman 批量导出接口
测试工具·postman
Cc_Davis_cC15 小时前
postman发送请求报文到后台中文乱码
测试工具·postman
一个幽默的程序员15 小时前
Postman 集合如何快速分享给团队?
测试工具·postman
一个幽默的程序员1 天前
Postman 如何发送 Post 请求上传文件? 全面指南
测试工具·postman