# AutomationFrameworkSelenium **Repository Path**: xianyunhege/automation-framework-selenium ## Basic Information - **Project Name**: AutomationFrameworkSelenium - **Description**: 这是一个基于Selenium WebDriver 4.x + TestNG + Java 构建的企业级自动化测试框架。框架采用现代化的设计模式和最佳实践,提供了完整的 Web 应用自动化测试解决方案。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2025-07-20 - **Last Updated**: 2025-10-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Selenium Java TestNG 自动化测试框架详细文档 ## 📋 目录 1. [框架概述](#框架概述) 2. [技术架构](#技术架构) 3. [核心特性](#核心特性) 4. [项目结构](#项目结构) 5. [环境配置](#环境配置) 6. [快速开始](#快速开始) 7. [核心组件详解](#核心组件详解) 8. [测试用例编写指南](#测试用例编写指南) 9. [数据驱动测试](#数据驱动测试) 10. [报告生成](#报告生成) 11. [并行执行](#并行执行) 12. [最佳实践](#最佳实践) 13. [常见问题](#常见问题) ## 🎯 框架概述 这是一个基于 **Selenium WebDriver 4.x + TestNG + Java** 构建的企业级自动化测试框架。框架采用现代化的设计模式和最佳实践,提供了完整的 Web 应用自动化测试解决方案。 ### 🌟 设计理念 - **模块化设计**:高度解耦的组件架构 - **可扩展性**:支持多项目、多环境测试 - **易维护性**:清晰的代码结构和文档 - **高效执行**:支持并行测试和分布式执行 - **丰富报告**:多种报告格式和通知方式 ## 🏗️ 技术架构 ### 核心技术栈 ``` ┌─────────────────────────────────────────────────────────┐ │ 测试层 (Test Layer) │ ├─────────────────────────────────────────────────────────┤ │ TestNG + Allure + ExtentReports + 自定义监听器 │ ├─────────────────────────────────────────────────────────┤ │ 页面层 (Page Layer) │ ├─────────────────────────────────────────────────────────┤ │ Page Object Model + WebUI 关键字库 │ ├─────────────────────────────────────────────────────────┤ │ 驱动层 (Driver Layer) │ ├─────────────────────────────────────────────────────────┤ │ Selenium WebDriver 4.x + ThreadGuard + 工厂模式 │ ├─────────────────────────────────────────────────────────┤ │ 工具层 (Utils Layer) │ ├─────────────────────────────────────────────────────────┤ │ Excel/JSON处理 + 邮件发送 + 截图录屏 + 数据生成 │ └─────────────────────────────────────────────────────────┘ ``` ### 依赖版本 - **Java**: 17+ - **Selenium WebDriver**: 4.29.0 - **TestNG**: 7.11.0 - **Allure**: 2.29.1 - **ExtentReports**: 5.1.2 - **Apache POI**: 5.4.0 - **DataFaker**: 2.4.2 ## ✨ 核心特性 ### 🚀 测试执行特性 - ✅ **多浏览器支持**: Chrome, Firefox, Edge, Safari - ✅ **并行执行**: 方法级、类级、套件级并行 - ✅ **分布式执行**: Selenium Grid 和 Docker 支持 - ✅ **无头模式**: 支持 Chrome 和 Firefox 无头执行 - ✅ **失败重试**: 自动重试失败的测试用例 - ✅ **智能等待**: 页面加载检测和自定义等待策略 ### 📊 数据管理特性 - ✅ **数据驱动**: Excel、JSON、Properties 文件支持 - ✅ **数据生成**: DataFaker 集成,支持多语言假数据 - ✅ **数据加密**: 敏感数据加密存储 - ✅ **配置管理**: 多环境配置文件管理 ### 📈 报告和通知特性 - ✅ **多种报告**: ExtentReports、Allure报告 - ✅ **截图功能**: 失败、成功、跳过步骤截图 - ✅ **视频录制**: 测试执行过程录制 - ✅ **邮件通知**: 测试结果邮件发送 - ✅ **报告压缩**: 自动压缩和归档 ### 🛠️ 开发特性 - ✅ **Page Object Model**: 标准 POM 设计模式 - ✅ **关键字驱动**: 丰富的 WebUI 关键字库 - ✅ **注解支持**: 自定义测试注解 - ✅ **日志系统**: Log4j2 集成 - ✅ **异常处理**: 自定义异常体系 ## 📁 项目结构 ``` AutomationFrameworkSelenium/ ├── src/ │ ├── main/java/com/fm/ │ │ ├── annotations/ # 自定义注解 │ │ │ └── FrameworkAnnotation.java │ │ ├── config/ # 配置管理 │ │ │ ├── ConfigFactory.java │ │ │ └── Configuration.java │ │ ├── constants/ # 常量定义 │ │ │ └── FrameworkConstants.java │ │ ├── driver/ # 驱动管理 │ │ │ ├── BrowserFactory.java │ │ │ ├── DriverManager.java │ │ │ └── TargetFactory.java │ │ ├── enums/ # 枚举类型 │ │ │ ├── AuthorType.java │ │ │ ├── Browser.java │ │ │ ├── CategoryType.java │ │ │ ├── FailureHandling.java │ │ │ ├── Platform.java │ │ │ ├── Project.java │ │ │ └── Target.java │ │ ├── exceptions/ # 自定义异常 │ │ │ ├── FrameworkException.java │ │ │ ├── HeadlessNotSupportedException.java │ │ │ ├── InvalidPathForExcelException.java │ │ │ ├── InvalidPathForExtentReportFileException.java │ │ │ ├── InvalidPathForFilesException.java │ │ │ ├── InvalidRemoteWebDriverURLException.java │ │ │ └── TargetNotValidException.java │ │ ├── helpers/ # 辅助工具类 │ │ │ ├── CaptureHelpers.java │ │ │ ├── DatabaseHelpers.java │ │ │ ├── ExcelHelpers.java │ │ │ ├── FileHelpers.java │ │ │ ├── JsonHelpers.java │ │ │ ├── PropertiesHelpers.java │ │ │ ├── ScreenRecorderHelpers.java │ │ │ └── SystemHelpers.java │ │ ├── keywords/ # 关键字库 │ │ │ └── WebUI.java │ │ ├── mail/ # 邮件功能 │ │ │ ├── EmailAttachmentsSender.java │ │ │ └── EmailConfig.java │ │ ├── reports/ # 报告管理 │ │ │ ├── AllureManager.java │ │ │ ├── ExtentReportManager.java │ │ │ ├── ExtentTestManager.java │ │ │ └── TelegramManager.java │ │ └── utils/ # 工具类 │ │ ├── BrowserInfoUtils.java │ │ ├── DataFakerUtils.java │ │ ├── DataGenerateUtils.java │ │ ├── DateUtils.java │ │ ├── DecodeUtils.java │ │ ├── EmailSendUtils.java │ │ ├── IconUtils.java │ │ ├── JsonUtils.java │ │ ├── LanguageUtils.java │ │ ├── LocalStorageUtils.java │ │ ├── LogUtils.java │ │ ├── ObjectUtils.java │ │ ├── ReportUtils.java │ │ └── ZipUtils.java │ └── test/ │ ├── java/com/fm/ │ │ ├── common/ # 基础测试类 │ │ │ └── BaseTest.java │ │ ├── dataprovider/ # 数据提供者 │ │ │ ├── DataProviderAddProduct.java │ │ │ └── DataProviderManager.java │ │ ├── listeners/ # 测试监听器 │ │ │ ├── AllureListener.java │ │ │ ├── AnnotationTransformer.java │ │ │ ├── Retry.java │ │ │ └── TestListener.java │ │ └── projects/ # 测试项目 │ │ ├── cms/ # CMS 项目测试 │ │ └── crm/ # CRM 项目测试 │ └── resources/ │ ├── config/ # 配置文件 │ │ ├── config.properties │ │ ├── data.properties │ │ └── config.json │ ├── suites/ # TestNG 套件 │ └── testdata*/ # 测试数据 ├── exports/ # 导出文件 │ ├── ExtentReports/ # 测试报告 │ └── ExportData/ # 截图和视频 ├── docs/ # JavaDoc 文档 ├── pom.xml # Maven 配置 ├── README.md # 英文说明 ├── README_CN.md # 中文说明 └── CHANGELOG.txt # 更新日志 ``` ## ⚙️ 环境配置 ### 系统要求 - **操作系统**: Windows 10+, macOS 10.14+, Linux Ubuntu 18.04+ - **Java**: JDK 17 或更高版本 - **Maven**: 3.6.0 或更高版本 - **IDE**: IntelliJ IDEA 或 Eclipse (推荐 IntelliJ IDEA) ### 浏览器驱动 框架使用 Selenium Manager 自动管理驱动,无需手动下载配置。支持的浏览器: - Chrome (推荐) - Firefox - Edge - Safari (仅 macOS) ### 配置文件说明 #### config.properties - 主配置文件 ```properties # 基础配置 AUTHOR = BROWSER = chrome # 默认浏览器 HEADLESS = false # 是否无头模式 TARGET = local # 执行目标: local/remote # 等待时间配置 WAIT_DEFAULT = 5 # 默认等待时间(秒) WAIT_IMPLICIT = 10 # 隐式等待时间(秒) WAIT_EXPLICIT = 10 # 显式等待时间(秒) WAIT_PAGE_LOADED = 40 # 页面加载等待时间(秒) ACTIVE_PAGE_LOADED = true # 是否启用页面加载检测 WAIT_SLEEP_STEP = 0 # 每步操作间隔时间(秒) # 测试环境 URL URL_CRM = https://rise.anhtester.com/signin # Selenium Grid 配置 REMOTE_URL = localhost # Grid Hub 地址 REMOTE_PORT = 4444 # Grid Hub 端口 # 报告配置 PROJECT_NAME = Automation Framework Selenium REPORT_TITLE = Report | Automation Framework Selenium EXTENT_REPORT_NAME = ExtentReports EXTENT_REPORT_FOLDER = exports/ExtentReports OVERRIDE_REPORTS = yes # 是否覆盖报告 OPEN_REPORTS_AFTER_EXECUTION = no # 执行后是否自动打开报告 # 截图配置 SCREENSHOT_PASSED_TCS = yes # 通过用例截图 SCREENSHOT_FAILED_TCS = yes # 失败用例截图 SCREENSHOT_SKIPPED_TCS = no # 跳过用例截图 SCREENSHOT_ALL_STEPS = no # 所有步骤截图 # 视频录制 VIDEO_RECORD = no # 是否录制视频 # 邮件通知 SEND_EMAIL_TO_USERS = no # 是否发送邮件 SEND_REPORT_TO_TELEGRAM = no # 是否发送到 Telegram TELEGRAM_TOKEN = # Telegram Bot Token TELEGRAM_CHATID = # Telegram Chat ID # 其他配置 ZIP_FOLDER = no # 是否压缩报告 RETRY_TEST_FAIL = 1 # 失败重试次数 LOCATE = vi # DataFaker 语言设置 ``` #### data.properties - 数据文件配置 ```properties # 测试数据文件路径 EXCEL_DATA_FILE_PATH = src/test/resources/testdataCRM/ClientsDataExcel.xlsx JSON_DATA_FILE_PATH = src/test/resources/config/config.json # 默认测试数据 email=admin@example.com password=123456 ``` ## 🚀 快速开始 ### 1. 克隆项目 ```bash git clone https://gitee.com/xianyunhege/automation-framework-selenium.git cd AutomationFrameworkSelenium ``` ### 2. 安装依赖 ```bash mvn clean install ``` ### 3. 运行示例测试 #### 基础运行命令 ```bash # 运行默认测试套件(SignIn-simple.xml) mvn test # 运行指定的测试套件 mvn test -Dsuite=src/test/resources/suites/CRM/Clients-simple.xml # 运行所有测试 mvn test -Dsuite=src/test/resources/suites/SuiteAll.xml ``` #### 高级运行选项 ```bash # 指定浏览器类型 mvn test -Dsuite=src/test/resources/suites/CRM/SignIn-simple.xml -DBROWSER=chrome mvn test -Dsuite=src/test/resources/suites/CRM/SignIn-simple.xml -DBROWSER=firefox mvn test -Dsuite=src/test/resources/suites/CRM/SignIn-simple.xml -DBROWSER=edge # 无头模式运行 mvn test -Dsuite=src/test/resources/suites/CRM/SignIn-simple.xml -DHEADLESS=true # 指定运行环境 mvn test -Dsuite=src/test/resources/suites/CRM/SignIn-simple.xml -DENVIRONMENT=staging # 组合参数使用 mvn test -Dsuite=src/test/resources/suites/CRM/SignIn-simple.xml -DBROWSER=firefox -DHEADLESS=true -DENVIRONMENT=production ``` #### 编码说明 - 所有日志和报告现在都使用UTF-8编码 - 支持中文和其他Unicode字符的正确显示 - ExtentReport和Allure报告都支持UTF-8编码 ### 4. 查看报告 测试完成后,报告将生成在 `exports/ExtentReports/` 目录下。 ## 🔧 核心组件详解 ### 1. WebUI 关键字库 WebUI 类是框架的核心,提供了 200+ 个封装好的 Selenium 操作方法,涵盖了 Web 自动化测试的所有常用场景。 #### 🔧 基础工具方法 ```java // 智能等待和休眠 WebUI.smartWait(); // 智能等待机制 WebUI.sleep(int second); // 线程休眠 WebUI.getSoftAssert(); // 获取软断言对象 ``` #### 📸 截图和录制功能 ```java // 截图功能 WebUI.takeScreenshot(String screenshotName); // 截取整页截图 WebUI.takeElementScreenshot(By by, String screenshotName); // 截取元素截图 WebUI.addScreenshotToReport(String screenshotName); // 添加截图到报告 // 录制功能 WebUI.startRecording(); // 开始录制 WebUI.stopRecording(); // 停止录制 ``` #### 📁 文件下载管理 ```java // 下载文件验证 WebUI.verifyDownloadedFile(String fileName); // 验证文件下载 WebUI.deleteAllFileInDownloadDirectory(); // 清空下载目录 WebUI.countFilesInDownloadDirectory(); // 统计下载文件数量 ``` #### 🌐 浏览器和页面操作 ```java // 页面导航 WebUI.openWebsite(String URL); // 打开网站 WebUI.getCurrentUrl(); // 获取当前URL WebUI.getPageTitle(); // 获取页面标题 WebUI.reloadPage(); // 刷新页面 WebUI.navigateToUrl(String URL); // 导航到URL // 页面状态检查 WebUI.verifyPageTitle(String expectedTitle); // 验证页面标题 WebUI.verifyPageUrl(String expectedUrl); // 验证页面URL ``` #### 🖱️ 元素交互操作 ##### 点击操作 ```java // 基础点击 WebUI.clickElement(By by); // 点击元素 WebUI.clickElement(By by, int timeout); // 带超时的点击 WebUI.clickElementWithJs(By by); // 使用JavaScript点击 WebUI.clickLinkText(String linkText); // 点击链接文本 WebUI.rightClickElement(By by); // 右键点击 WebUI.doubleClickElement(By by); // 双击元素 ``` ##### 文本输入操作 ```java // 文本设置 WebUI.setText(By by, String value); // 设置文本 WebUI.setText(By by, String value, Keys keys); // 设置文本并按键 WebUI.clearText(By by); // 清除文本 WebUI.clearTextCtrlA(By by); // 使用Ctrl+A清除文本 WebUI.clearAndFillText(By by, String value); // 清除并填入文本 // 按键操作 WebUI.sendKeys(By by, Keys keys); // 发送按键到元素 WebUI.sendKeys(Keys keys); // 发送按键到当前位置 ``` #### 📋 元素属性获取 ```java // 获取元素信息 WebUI.getTextElement(By by); // 获取元素文本 WebUI.getAttributeElement(By by, String attributeName); // 获取元素属性 WebUI.getCssValueElement(By by, String cssName); // 获取CSS值 WebUI.getSizeElement(By by); // 获取元素尺寸 WebUI.getLocationElement(By by); // 获取元素位置 WebUI.getTagNameElement(By by); // 获取标签名 // 获取元素集合 WebUI.getListElementsText(By by); // 获取元素列表文本 WebUI.getWebElements(By by); // 获取WebElement列表 WebUI.getWebElement(By by); // 获取单个WebElement ``` #### ✅ 元素状态检查 ```java // 元素存在性检查 WebUI.checkElementExist(By by); // 检查元素是否存在 WebUI.checkElementExist(By by, int maxRetries, int waitTimeMillis); // 带重试的元素存在检查 // 元素状态检查 WebUI.isElementVisible(By by); // 检查元素是否可见 WebUI.isElementVisible(By by, int timeout); // 带超时的可见性检查 WebUI.isElementPresent(By by); // 检查元素是否存在 WebUI.isElementClickable(By by); // 检查元素是否可点击 WebUI.isElementEnabled(By by); // 检查元素是否启用 WebUI.isElementSelected(By by); // 检查元素是否选中 ``` #### 📝 下拉框和选择操作 ```java // 下拉框选择 WebUI.selectOptionByText(By by, String text); // 按文本选择选项 WebUI.selectOptionByValue(By by, String value); // 按值选择选项 WebUI.selectOptionByIndex(By by, int index); // 按索引选择选项 // 获取选择信息 WebUI.getFirstSelectedOption(By by); // 获取首选项 WebUI.getAllSelectedOptions(By by); // 获取所有选中项 WebUI.getAllOptionsInDropdown(By by); // 获取所有选项 // 多选操作 WebUI.deselectOptionByText(By by, String text); // 按文本取消选择 WebUI.deselectOptionByValue(By by, String value); // 按值取消选择 WebUI.deselectOptionByIndex(By by, int index); // 按索引取消选择 WebUI.deselectAllOptions(By by); // 取消所有选择 ``` #### 🖱️ 鼠标操作 ```java // 鼠标移动和悬停 WebUI.hoverElement(By by); // 悬停元素 WebUI.moveToElement(By by); // 移动到元素 WebUI.moveToOffset(int X, int Y); // 移动到偏移位置 // 拖拽操作 WebUI.dragAndDrop(By fromElement, By toElement); // 拖拽操作 WebUI.dragAndDropToOffset(By fromElement, int X, int Y); // 拖拽到指定位置 WebUI.dragAndDropHTML5(By fromElement, By toElement); // HTML5拖拽 ``` #### 📜 滚动操作 ```java // 滚动到元素 WebUI.scrollToElement(By by); // 滚动到元素 WebUI.scrollToElementAtTop(By by); // 滚动到元素顶部 WebUI.scrollToElementAtBottom(By by); // 滚动到元素底部 // 滚动到位置 WebUI.scrollToPosition(int X, int Y); // 滚动到指定位置 WebUI.scrollToTop(); // 滚动到页面顶部 WebUI.scrollToBottom(); // 滚动到页面底部 ``` #### 🪟 窗口和框架切换 ##### 窗口操作 ```java // 窗口切换 WebUI.switchToWindowOrTabByPosition(int position); // 按位置切换窗口 WebUI.switchToWindowOrTabByTitle(String title); // 按标题切换窗口 WebUI.switchToWindowOrTabByUrl(String url); // 按URL切换窗口 WebUI.switchToMainWindow(); // 切换到主窗口 WebUI.switchToMainWindow(String originalWindow); // 按ID切换到主窗口 WebUI.switchToLastWindow(); // 切换到最后窗口 // 窗口管理 WebUI.openAndSwitchNewTab(); // 打开新标签页 WebUI.openAndSwitchNewWindow(); // 打开新窗口 WebUI.closeCurrentWindow(); // 关闭当前窗口 WebUI.verifyTotalOfWindowsOrTab(int number); // 验证窗口数量 ``` ##### 框架操作 ```java // 框架切换 WebUI.switchToFrameByIndex(int index); // 按索引切换框架 WebUI.switchToFrameByIdOrName(String IdOrName); // 按ID或名称切换框架 WebUI.switchToFrameByElement(By by); // 按元素切换框架 WebUI.switchToDefaultContent(); // 切换到默认内容 ``` #### 🚨 弹窗处理 ```java // 弹窗操作 WebUI.acceptAlert(); // 接受弹窗 WebUI.dismissAlert(); // 取消弹窗 WebUI.getTextAlert(); // 获取弹窗文本 WebUI.setTextAlert(String text); // 设置弹窗文本 WebUI.verifyAlertPresent(int timeOut); // 验证弹窗存在 ``` #### 📊 表格数据处理 ```java // 表格数据验证 WebUI.checkEqualsValueOnTableByColumn(int column, String value); // 检查表格列值相等 WebUI.checkContainsValueOnTableByColumn(int column, String value); // 检查表格列值包含 WebUI.checkContainsValueOnTableByColumn(int column, String value, String xpath); // 自定义xpath检查表格 // 表格数据获取 WebUI.getValueTableByColumn(int column); // 获取表格列值 ``` #### ✔️ 验证断言方法 ```java // 基础验证 WebUI.verifyEquals(Object actual, Object expected); // 验证相等 WebUI.verifyEquals(Object actual, Object expected, String message); // 带消息的相等验证 WebUI.verifyContains(String actual, String expected); // 验证包含 WebUI.verifyContains(String actual, String expected, String message); // 带消息的包含验证 WebUI.verifyTrue(boolean condition); // 验证为真 WebUI.verifyTrue(boolean condition, String message); // 带消息的真值验证 // 元素验证 WebUI.verifyElementText(By by, String text); // 验证元素文本 WebUI.verifyElementAttributeValue(By by, String attributeName, String attributeValue); // 验证元素属性值 WebUI.verifyElementHasAttribute(By by, String attributeName, int timeOut); // 验证元素有属性 WebUI.verifyElementPresent(By by); // 验证元素存在 WebUI.verifyElementVisible(By by); // 验证元素可见 WebUI.verifyElementClickable(By by); // 验证元素可点击 WebUI.verifyElementNotPresent(By by); // 验证元素不存在 ``` #### ⏱️ 等待机制 ##### 元素等待 ```java // 基础等待 WebUI.waitForElementVisible(By by); // 等待元素可见 WebUI.waitForElementVisible(By by, int second); // 带超时的可见等待 WebUI.waitForElementClickable(By by); // 等待元素可点击 WebUI.waitForElementClickable(By by, long timeOut); // 带超时的可点击等待 WebUI.waitForElementPresent(By by); // 等待元素存在 WebUI.waitForElementPresent(By by, long timeOut); // 带超时的存在等待 // 特殊等待 WebUI.waitForAlertPresent(); // 等待弹窗出现 WebUI.waitForAlertPresent(int timeOut); // 带超时的弹窗等待 WebUI.waitForElementHasAttribute(By by, String attributeName); // 等待元素有属性 ``` ##### 页面等待 ```java // 页面加载等待 WebUI.waitForPageLoaded(); // 等待页面加载完成 WebUI.waitForPageLoaded(int timeOut); // 带超时的页面加载等待 WebUI.waitForJQueryLoad(); // 等待jQuery加载完成 WebUI.waitForAngularLoad(); // 等待Angular加载完成 ``` #### 📋 HTML5表单验证 ```java // HTML5验证 WebUI.verifyHTML5RequiredField(By by); // 验证HTML5必填字段 WebUI.verifyHTML5InvalidField(By by); // 验证HTML5无效字段 ``` #### 📁 文件操作 ```java // 文件上传 WebUI.uploadFileWithSendKeys(By by, String filePath); // 使用sendKeys上传文件 WebUI.uploadFileWithLocalForm(By by, String filePath); // 使用本地表单上传文件 // 文件处理 WebUI.uploadMultipleFiles(By by, String[] filePaths); // 上传多个文件 ``` #### 🎯 高级操作 ```java // JavaScript执行 WebUI.executeJavaScript(String script); // 执行JavaScript WebUI.executeJavaScript(String script, Object... args); // 带参数执行JavaScript // Cookie操作 WebUI.addCookie(String name, String value); // 添加Cookie WebUI.getCookie(String name); // 获取Cookie WebUI.deleteCookie(String name); // 删除Cookie WebUI.deleteAllCookies(); // 删除所有Cookie // 本地存储操作 WebUI.setLocalStorage(String key, String value); // 设置本地存储 WebUI.getLocalStorage(String key); // 获取本地存储 WebUI.removeLocalStorage(String key); // 删除本地存储 WebUI.clearLocalStorage(); // 清空本地存储 ``` #### 📱 移动端操作 ```java // 触摸操作 WebUI.tap(By by); // 点击操作 WebUI.swipe(int startX, int startY, int endX, int endY); // 滑动操作 WebUI.pinch(By by); // 缩放操作 WebUI.zoom(By by); // 放大操作 ``` #### 🔍 元素查找增强 ```java // 高级查找 WebUI.findElementByText(String text); // 按文本查找元素 WebUI.findElementByPartialText(String partialText); // 按部分文本查找元素 WebUI.findElementsByAttribute(String attribute, String value); // 按属性查找元素 WebUI.findElementsContainingText(String text); // 查找包含文本的元素 ``` ### WebUI 使用最佳实践 #### 1. 基础测试流程 ```java public class LoginTest extends BaseTest { @Test public void testLogin() { // 1. 打开页面 WebUI.openWebsite("https://example.com/login"); // 2. 等待页面加载 WebUI.waitForPageLoaded(); // 3. 输入用户名密码 WebUI.setText(By.id("username"), "admin"); WebUI.setText(By.id("password"), "password123"); // 4. 点击登录 WebUI.clickElement(By.id("login-btn")); // 5. 验证登录成功 WebUI.verifyElementPresent(By.id("dashboard")); WebUI.verifyContains(WebUI.getCurrentUrl(), "/dashboard"); // 6. 截图记录 WebUI.takeScreenshot("login_success"); } } ``` #### 2. 复杂表单操作 ```java @Test public void testComplexForm() { WebUI.openWebsite("https://example.com/form"); // 文本输入 WebUI.setText(By.id("firstName"), "John"); WebUI.setText(By.id("lastName"), "Doe"); // 下拉框选择 WebUI.selectOptionByText(By.id("country"), "Vietnam"); WebUI.selectOptionByValue(By.id("city"), "hanoi"); // 复选框和单选框 WebUI.clickElement(By.id("newsletter")); WebUI.clickElement(By.xpath("//input[@name='gender'][@value='male']")); // 文件上传 WebUI.uploadFileWithSendKeys(By.id("avatar"), "path/to/image.jpg"); // 提交表单 WebUI.clickElement(By.id("submit")); // 验证结果 WebUI.verifyElementText(By.id("success-message"), "Form submitted successfully"); } ``` #### 3. 表格数据验证 ```java @Test public void testTableData() { WebUI.openWebsite("https://example.com/users"); // 搜索用户 WebUI.setText(By.id("search"), "John"); WebUI.clickElement(By.id("search-btn")); // 验证搜索结果 WebUI.checkContainsValueOnTableByColumn(2, "John"); // 第2列包含"John" WebUI.checkEqualsValueOnTableByColumn(3, "Active"); // 第3列等于"Active" // 获取表格数据 ArrayList names = WebUI.getValueTableByColumn(2); for (String name : names) { System.out.println("User name: " + name); } } ``` #### 4. 多窗口操作 ```java @Test public void testMultipleWindows() { WebUI.openWebsite("https://example.com"); // 点击链接打开新窗口 WebUI.clickElement(By.linkText("Open New Window")); // 切换到新窗口 WebUI.switchToWindowOrTabByTitle("New Window Title"); // 在新窗口中操作 WebUI.verifyElementPresent(By.id("new-window-content")); // 关闭当前窗口 WebUI.closeCurrentWindow(); // 切换回主窗口 WebUI.switchToMainWindow(); // 验证回到主窗口 WebUI.verifyElementPresent(By.id("main-content")); } ``` ### 2. 驱动管理器 #### DriverManager - 线程安全的驱动管理 ```java public class DriverManager { private static final ThreadLocal driver = new ThreadLocal<>(); public static void setDriver(WebDriver driver) { DriverManager.driver.set(driver); } public static WebDriver getDriver() { return driver.get(); } public static void quit() { if (driver.get() != null) { driver.get().quit(); driver.remove(); } } } ``` #### TargetFactory - 驱动创建工厂 ```java public class TargetFactory { public WebDriver createInstance(String browser) { Target target = Target.valueOf(FrameworkConstants.TARGET.toUpperCase()); switch (target) { case LOCAL: return BrowserFactory.createLocalDriver(browser); case REMOTE: return BrowserFactory.createRemoteDriver(browser); default: throw new TargetNotValidException(target.toString()); } } } ``` ### 3. 配置管理 #### Configuration 接口 - 使用 Owner 库 ```java @LoadPolicy(LoadType.MERGE) @Sources({ "system:properties", "system:env", "file:./src/test/resources/config/config.properties", "file:./src/test/resources/config/data.properties" }) public interface Configuration extends Config { @Key("BROWSER") String BROWSER(); @Key("HEADLESS") Boolean HEADLESS(); @Key("URL_CRM") String URL_CRM(); } ``` ### 4. 数据处理 #### ExcelHelpers - Excel 数据读取 ```java public class ExcelHelpers { public void setExcelFile(String excelPath, String sheetName) { // 设置 Excel 文件和工作表 } public String getCellData(int row, String columnName) { // 根据行号和列名获取数据 } public Object[][] getDataHashTable(String excelPath, String sheetName, int startRow, int endRow) { // 获取 HashTable 格式的测试数据 } } ``` #### JsonHelpers - JSON 数据处理 ```java public class JsonHelpers { public static String getValue(String json, String key) { // 从 JSON 字符串中获取值 } public static void setValueToFile(String jsonFile, String key, String value) { // 设置值到 JSON 文件 } } ``` ### 5. 报告系统 #### ExtentReportManager - ExtentReports 集成 ```java public class ExtentReportManager { public static void initReports() { // 初始化报告 } public static void flushReports() { // 生成报告 } public static void addScreenShot(String screenName) { // 添加截图到报告 } } ``` #### AllureManager - Allure 集成 ```java public class AllureManager { @Step("{0}") public static void saveTextLog(String message) { // 保存文本日志 } public static void takeScreenshotStep() { // 截图步骤 } } ``` ## 📝 测试用例编写指南 ### 1. 基础测试类结构 ```java @Epic("Regression Test CRM") @Feature("Login Test") public class LoginTest extends BaseTest { private LoginPage loginPage; public LoginTest() { loginPage = new LoginPage(); } @Test(priority = 1, description = "Valid login test") public void testValidLogin() { loginPage.openLoginPage(); loginPage.login("admin@example.com", "password123"); loginPage.verifyLoginSuccess(); } } ``` ### 2. Page Object Model 实现 ```java public class LoginPage extends CommonPageCRM { // 页面元素定位 private By inputEmail = By.id("email"); private By inputPassword = By.id("password"); private By buttonLogin = By.xpath("//button[text()='Login']"); private By messageWelcome = By.id("welcome-message"); // 页面操作方法 public void openLoginPage() { WebUI.openWebsite(FrameworkConstants.URL_LOGIN); WebUI.verifyElementPresent(inputEmail); } public void login(String email, String password) { WebUI.setText(inputEmail, email); WebUI.setText(inputPassword, password); WebUI.clickElement(buttonLogin); WebUI.waitForPageLoaded(); } public void verifyLoginSuccess() { WebUI.verifyElementPresent(messageWelcome); WebUI.verifyContains(WebUI.getCurrentUrl(), "/dashboard"); } } ``` ### 3. 数据驱动测试 #### 使用 Excel 数据 ```java @Test(dataProvider = "getLoginData", dataProviderClass = DataProviderManager.class) public void testLoginWithExcelData(Hashtable data) { loginPage.openLoginPage(); loginPage.login( data.get("email"), data.get("password") ); loginPage.verifyLoginResult(data.get("expectedResult")); } ``` #### DataProvider 实现 ```java @DataProvider(name = "getLoginData", parallel = true) public static Object[][] getLoginData() { ExcelHelpers excel = new ExcelHelpers(); return excel.getDataHashTable( FrameworkConstants.EXCEL_LOGIN_DATA, "LoginData", 1, 5 ); } ``` ### 4. 自定义注解使用 ```java @FrameworkAnnotation( author = {AuthorType.AnVo}, category = {CategoryType.REGRESSION, CategoryType.SMOKE} ) @Test(priority = 1, description = "Critical login functionality") public void testCriticalLogin() { // 测试实现 } ``` ## 📊 数据驱动测试 ### 1. Excel 数据格式 #### 登录测试数据 (Login.xlsx) | TestCaseName | email | password | expectedResult | |--------------|-------|----------|----------------| | TC01_ValidLogin | admin@test.com | password123 | success | | TC02_InvalidEmail | invalid@test.com | password123 | failed | | TC03_InvalidPassword | admin@test.com | wrongpass | failed | #### 客户数据 (ClientData.xlsx) | TestCaseName | CompanyName | Owner | Address | City | State | |--------------|-------------|-------|---------|------|-------| | TC01_AddClient | ABC Corp | John Doe | 123 Main St | Hanoi | Vietnam | ### 2. JSON 数据格式 ```json { "loginData": { "validUser": { "email": "admin@example.com", "password": "password123" }, "invalidUser": { "email": "invalid@example.com", "password": "wrongpass" } }, "testEnvironment": { "baseUrl": "https://example.com", "timeout": 30 } } ``` ### 3. 数据模型类 ```java @Data public class LoginModel { private static final String testCaseName = "TestCaseName"; private static final String email = "email"; private static final String password = "password"; private static final String expectedResult = "expectedResult"; // Getter 方法 public static String getTestCaseName() { return testCaseName; } public static String getEmail() { return email; } public static String getPassword() { return password; } public static String getExpectedResult() { return expectedResult; } } ``` ### 4. 数据加密 ```java // 加密敏感数据 String encryptedPassword = DecodeUtils.encrypt("password123"); // 解密数据 String decryptedPassword = DecodeUtils.decrypt(encryptedPassword); ``` ## 📈 报告生成 ### 1. ExtentReports 配置 框架自动生成 ExtentReports,包含以下信息: - 测试执行概览 - 详细的测试步骤 - 截图和日志 - 系统信息 - 执行时间统计 ### 2. Allure 报告 ```bash # 生成 Allure 报告 mvn allure:report # 启动 Allure 服务器 mvn allure:serve ``` ### 3. 自定义报告内容 ```java // 添加测试步骤 @Step("Login with email: {email}") public void loginStep(String email, String password) { WebUI.setText(inputEmail, email); WebUI.setText(inputPassword, password); WebUI.clickElement(buttonLogin); } // 添加附件 AllureManager.saveTextLog("Login attempt with: " + email); AllureManager.takeScreenshotStep(); ``` ### 4. 邮件报告 配置邮件发送: ```java public class EmailConfig { public static final String SERVER = "smtp.gmail.com"; public static final String PORT = "587"; public static final String FROM = "your-email@gmail.com"; public static final String PASSWORD = "your-app-password"; } ``` ## ⚡ 并行执行 ### 1. TestNG 并行配置 #### 方法级并行 ```xml ``` #### 类级并行 ```xml ``` ### 2. 线程安全保证 ```java // 使用 ThreadGuard 保护 WebDriver WebDriver driver = ThreadGuard.protect(new TargetFactory().createInstance(browser)); // ThreadLocal 管理驱动实例 private static final ThreadLocal driver = new ThreadLocal<>(); ``` ### 3. Selenium Grid 配置 #### Hub 启动 ```bash java -jar selenium-server-4.x.x.jar hub ``` #### Node 启动 ```bash java -jar selenium-server-4.x.x.jar node --detect-drivers ``` #### 配置远程执行 ```properties TARGET = remote REMOTE_URL = localhost REMOTE_PORT = 4444 ``` ## 🎯 最佳实践 ### 1. 代码组织 - **单一职责**: 每个页面类只负责一个页面的操作 - **命名规范**: 使用清晰、有意义的命名 - **注释文档**: 为复杂逻辑添加注释 - **版本控制**: 使用 Git 进行版本管理 ### 2. 元素定位 ```java // 推荐:使用稳定的定位策略 private By buttonSubmit = By.id("submit-btn"); // ID 最稳定 private By inputEmail = By.name("email"); // Name 属性 private By linkLogout = By.linkText("Logout"); // 链接文本 private By titlePage = By.xpath("//h1[text()='Dashboard']"); // 精确 XPath // 避免:使用不稳定的定位 private By element = By.xpath("//div[1]/span[2]/a[3]"); // 位置依赖 private By button = By.className("btn btn-primary btn-lg"); // 多个类名 ``` ### 3. 等待策略 ```java // 推荐:使用显式等待 WebUI.waitForElementVisible(By.id("result"), 10); WebUI.waitForElementClickable(By.id("submit"), 5); // 避免:使用固定等待 Thread.sleep(5000); // 不推荐 ``` ### 4. 测试数据管理 ```java // 推荐:使用配置文件和数据文件 String email = PropertiesHelpers.getValue("admin.email"); String testData = excelHelpers.getCellData(1, "companyName"); // 避免:硬编码测试数据 String email = "admin@example.com"; // 不推荐 ``` ### 5. 异常处理 ```java // 推荐:使用框架的异常处理 try { WebUI.clickElement(buttonSubmit); } catch (Exception e) { LogUtils.error("Failed to click submit button: " + e.getMessage()); throw new FrameworkException("Submit operation failed"); } ``` ### 6. 测试用例设计 ```java // 推荐:独立的测试用例 @Test public void testAddNewClient() { // 准备测试数据 ClientData clientData = DataGenerator.generateClientData(); // 执行测试步骤 loginPage.login(adminUser); clientPage.addNewClient(clientData); // 验证结果 clientPage.verifyClientAdded(clientData); // 清理数据 clientPage.deleteClient(clientData.getClientId()); } ``` ## ❓ 常见问题 ### 1. 环境配置问题 **Q: 如何解决 Java 版本兼容性问题?** ```bash # 检查 Java 版本 java -version # 设置 JAVA_HOME export JAVA_HOME=/path/to/java17 ``` **Q: Maven 依赖下载失败怎么办?** ```bash # 清理并重新下载依赖 mvn clean install -U # 使用阿里云镜像 # 在 ~/.m2/settings.xml 中配置镜像 ``` ### 2. 浏览器驱动问题 **Q: 浏览器驱动版本不匹配?** - 框架使用 Selenium Manager 自动管理驱动 - 确保浏览器是最新版本 - 检查网络连接是否正常 **Q: 无头模式运行失败?** ```properties # 确保配置正确 HEADLESS = true BROWSER = chrome # 或 firefox ``` ### 3. 测试执行问题 **Q: 测试用例执行缓慢?** - 检查等待时间配置 - 使用并行执行 - 优化页面加载检测 **Q: 元素定位失败?** - 检查元素定位器是否正确 - 添加适当的等待时间 - 使用浏览器开发者工具验证 ### 4. 报告生成问题 **Q: ExtentReports 报告不显示截图?** - 检查截图路径配置 - 确保有写入权限 - 验证截图功能是否启用 **Q: Allure 报告生成失败?** ```bash # 检查 Allure 命令行工具 allure --version # 重新生成报告 mvn clean test allure:report ``` ### 5. 数据驱动问题 **Q: Excel 数据读取失败?** - 检查文件路径是否正确 - 确保 Excel 文件格式正确 - 验证工作表名称 **Q: 数据加密解密问题?** - 检查加密密钥配置 - 确保加密算法一致 - 验证数据格式 ### 6. 性能优化 **Q: 如何提高测试执行速度?** - 启用并行执行 - 优化等待策略 - 使用无头模式 - 减少不必要的截图 **Q: 内存使用过高?** - 及时关闭浏览器实例 - 清理临时文件 - 优化测试数据大小 ---