1. 项目概述基于JavaPlaywrightTestNG的UI自动化测试方案最近在重构团队的UI自动化测试框架时我选择了Playwright这个新兴的测试工具配合Java和TestNG搭建了一套高效的测试方案。这套组合拳在实际项目中表现非常出色特别是对于现代Web应用如SPA的测试支持相当完善。相比传统的Selenium方案Playwright的异步执行模型和内置等待机制让测试脚本更加稳定可靠。这个方案特别适合以下场景需要测试包含大量动态内容的现代Web应用现有Selenium测试存在大量flaky tests不稳定的测试用例团队已经具备Java技术栈希望复用现有测试基础设施需要跨浏览器Chromium/WebKit/Firefox的自动化测试能力2. 技术栈选型与核心组件2.1 为什么选择PlaywrightPlaywright是微软开源的现代化浏览器自动化工具相比Selenium有以下几个显著优势多浏览器支持一套API同时支持Chromium、WebKit和Firefox自动等待机制内置智能等待无需手动添加sleep网络拦截能力可以直接mock网络请求和响应设备模拟支持移动设备视口和User-Agent模拟视频录制测试过程可以自动录屏便于问题排查实际使用中发现Playwright对React/Vue等现代前端框架的支持特别好能自动等待动态加载的内容。2.2 TestNG作为测试框架的优势TestNG相比JUnit在测试组织和管理上更加强大灵活的测试分组(group)和依赖管理参数化测试支持更完善丰富的监听器(Listener)机制内置HTML报告生成并行测试执行能力2.3 Maven项目配置基础pom.xml依赖配置如下dependencies !-- Playwright Java SDK -- dependency groupIdcom.microsoft.playwright/groupId artifactIdplaywright/artifactId version1.40.0/version /dependency !-- TestNG -- dependency groupIdorg.testng/groupId artifactIdtestng/artifactId version7.8.0/version scopetest/scope /dependency !-- 日志框架 -- dependency groupIdorg.slf4j/groupId artifactIdslf4j-api/artifactId version2.0.7/version /dependency /dependencies3. 核心实现与最佳实践3.1 测试基类设计建议抽象一个基础测试类处理Playwright的初始化和清理public class BaseTest { protected Playwright playwright; protected Browser browser; protected BrowserContext context; protected Page page; BeforeSuite public void launchBrowser() { playwright Playwright.create(); browser playwright.chromium().launch( new BrowserType.LaunchOptions().setHeadless(false) ); } BeforeMethod public void createContext(ITestContext testContext) { context browser.newContext(); page context.newPage(); } AfterMethod public void closeContext() { context.close(); } AfterSuite public void closeBrowser() { browser.close(); playwright.close(); } }3.2 页面对象模式实现对于复杂的页面交互推荐使用页面对象模式public class LoginPage { private final Page page; // 定位器 private final Locator usernameInput; private final Locator passwordInput; private final Locator submitButton; public LoginPage(Page page) { this.page page; this.usernameInput page.locator(#username); this.passwordInput page.locator(#password); this.submitButton page.locator(#submit); } public void navigateToLogin() { page.navigate(https://example.com/login); } public void login(String username, String password) { usernameInput.fill(username); passwordInput.fill(password); submitButton.click(); } }3.3 测试用例编写示例结合TestNG的测试类示例public class LoginTests extends BaseTest { Test public void testSuccessfulLogin() { LoginPage loginPage new LoginPage(page); loginPage.navigateToLogin(); loginPage.login(validUser, validPass); assertThat(page).hasURL(https://example.com/dashboard); } Test public void testFailedLogin() { LoginPage loginPage new LoginPage(page); loginPage.navigateToLogin(); loginPage.login(invalid, credentials); Locator errorMessage page.locator(.error-message); assertThat(errorMessage).hasText(Invalid username or password); } }4. 高级特性与优化技巧4.1 并行测试执行TestNG支持通过XML配置实现并行测试suite namePlaywright Suite parallelmethods thread-count3 test nameLogin Tests classes class namecom.example.tests.LoginTests/ /classes /test /suite配合Playwright的BrowserContext隔离机制每个测试方法都会获得独立的浏览器上下文避免状态污染。4.2 网络请求拦截Playwright强大的网络API可以用于// 拦截所有请求 page.route(**/*, route - { if (route.request().url().contains(analytics)) { route.abort(); // 屏蔽分析请求 } else { route.continue_(); } }); // Mock API响应 page.route(**/api/user, route - { route.fulfill(new Route.FulfillOptions() .setContentType(application/json) .setBody({\name\:\Mock User\})); });4.3 视频录制与追踪在BrowserContext创建时启用录制BeforeMethod public void createContext(ITestContext testContext) { context browser.newContext(new Browser.NewContextOptions() .setRecordVideoDir(Paths.get(videos/)) .setRecordVideoSize(1280, 720)); // 同时启用追踪 context.tracing().start(new Tracing.StartOptions() .setScreenshots(true) .setSnapshots(true)); page context.newPage(); } AfterMethod public void closeContext(Method method) { // 保存追踪数据 context.tracing().stop(new Tracing.StopOptions() .setPath(Paths.get(traces/ method.getName() .zip))); context.close(); }5. 常见问题与解决方案5.1 元素定位问题Playwright提供了多种定位策略// 最佳实践优先级 page.locator(button:has-text(Submit)); // 1. 文本角色 page.locator(#login-form button.submit); // 2. CSS组合 page.locator(//button[idsubmit]); // 3. XPath最后考虑实际项目中发现使用文本定位配合适当的语义化角色通常最稳定避免了因CSS类名变化导致的测试失败。5.2 异步操作处理Playwright内置自动等待但某些场景需要显式等待// 等待元素可见 page.locator(.loading-spinner).waitFor(new Locator.WaitForOptions() .setState(WaitForSelectorState.HIDDEN)); // 等待网络请求完成 page.waitForResponse(response - response.url().contains(/api/data) response.status() 200, () - page.click(#load-data) );5.3 测试数据管理推荐使用TestNG的DataProvider实现参数化测试DataProvider(name loginCredentials) public Object[][] provideLoginData() { return new Object[][] { {admin, admin123, true}, {locked, password, false}, {, secret, false} }; } Test(dataProvider loginCredentials) public void testParameterizedLogin(String user, String pass, boolean expected) { LoginPage loginPage new LoginPage(page); loginPage.navigateToLogin(); loginPage.login(user, pass); if (expected) { assertThat(page).hasURL(containsString(/dashboard)); } else { assertThat(page.locator(.error)).isVisible(); } }6. 持续集成配置6.1 GitHub Actions示例name: Playwright Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - uses: actions/setup-javav3 with: java-version: 17 distribution: temurin - name: Run Playwright tests run: mvn test -Dheadlesstrue - name: Upload artifacts uses: actions/upload-artifactv3 if: always() with: name: test-results path: | target/surefire-reports/ videos/ traces/6.2 容器化执行Dockerfile配置示例FROM maven:3.8.6-eclipse-temurin-17 # 安装Playwright依赖 RUN apt-get update \ apt-get install -y libgbm-dev \ rm -rf /var/lib/apt/lists/* WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src CMD [mvn, test, -Dheadlesstrue]这套JavaPlaywrightTestNG的UI自动化测试方案在我们团队已经稳定运行半年多测试稳定性从原来的70%提升到了98%维护成本降低了约40%。特别是Playwright的自动等待和网络拦截功能大大减少了flaky tests的出现。对于已经使用Java技术栈的团队这个组合无疑是最平滑的现代化测试方案迁移路径。
企业数字化 ERP 产品动态
相关推荐
SAP Fiori Launchpad安全防护与权限管理实践 1. SAP Fiori Launchpad Designer 访问保护的核心挑战在SAP Fiori项目实施过程中,我们经常把大量精力放在界面美观度和功能可用性上,却容易忽视一个致命的安全隐患——普通用户意外获得Launchpad Designer的设计权限。这种情况远比想象中常见,… · 2026/11/2 13:00:58
深度学习在旅游推荐系统中的应用与优化 1. 项目概述:当深度学习遇上旅游推荐去年帮朋友优化他的旅游平台时,我发现传统推荐算法总把情侣用户和老年团推向相同的网红景点。这种"一刀切"的推荐方式,正是深度学习可以根治的痛点。基于深度学习的旅游推荐系统,本质… · 2026/11/2 13:00:58
LoRA技术解析:0.8%参数实现大模型高效微调 1. LoRA技术革命:用0.8%参数撬动100%大模型性能去年在部署一个金融领域的文本分类项目时,客户突然要求将基座模型从BERT-large换成新发布的LLaMA-2 7B。面对这个13倍参数量的庞然大物,我们的GPU集群差点崩溃——直到发现了LoRA这项黑科技。它… · 2026/11/2 13:00:58
健康饮水技术解析:从净水原理到场景化解决方案 1. 养水堂产品矩阵概述:健康饮水解决方案的全面布局 养水堂作为国内健康饮水领域的专业品牌,其产品矩阵构建逻辑始终围绕"场景化需求"这一核心理念展开。不同于传统净水设备厂商的单品思维,养水堂通过系统化的产品组合设计… · 2026/11/2 22:16:43
4400元换显卡只为本地跑大模型:RTX 4070 SUPER选卡与实测 电脑上的旧显卡曾经陪我好几年,游戏帧数看着还行,结果今年我发现它真正的短板根本不是帧率,而是显存。想正经在本地跑大模型,用 Ollama 跑一个 7B 量化模型,生成速度慢得像读逐字稿,把上下文稍微调长一点就… · 2026/11/2 22:16:43
Codex接入Agent Memory的三大硬冲突:源码级排查与解决策略 最近在处理 Codex 接入 TencentDB Agent Memory 的联调时,日志里反复出现一行报错: cc switch local proxy failed while handling codex endpoint /responses. provider... ,后面的内容还没打印完整,CI 构建就先红了。说实话&a… · 2026/11/2 22:16:43
腾讯开源WeKnora:Go语言打造企业级RAG+Agent+Wiki知识库框架 最近我在给团队做企业内部知识库选型,连续试了 Dify、RAGFlow 和几个 Python 写的 RAG 框架,最后把目光停在 WeKnora 上。这个由腾讯开源、用 Go 写出来的企业知识管理框架,把 RAG、Agent 和 Wiki 揉进了一个项目,单看定位就很特别… · 2026/11/2 22:16:43
六大NLP语言模型解析:技术路线与选型指南 过去做个文本分类,我得先分词、去停用词、算TF-IDF,再用SVM或贝叶斯跑一遍,最后调参数调到怀疑人生。现在呢?把需求原样丢给一个NLP语言模型,大部分时候它自己就能处理。这种变化的底层推手,就是GPT、Claud… · 2026/11/2 22:16:43
YOLOv5跨平台验证:PC端沙盒构建与RK3588部署基准线 1. 为什么先在PC端跑通YOLOv5,而不是直接烧录到香橙派RK3588?你拿到一块崭新的香橙派RK3588开发板,拆开包装、接上电源、插好HDMI线,满心期待地想立刻跑起YOLOv5做目标检测——结果卡在第一步:连Ubuntu系统都装不进去&… · 2026/11/2 22:15:42
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
雷达信号调制技术解析:从LFM到伪线性调频原理与应用 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
基于MAX14431与TM4C123的工业SPI隔离电路设计全攻略 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
PLFM_RADAR:相位线性调频雷达信号处理框架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 1:01:15
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18