首页 / Playwright 入门教程 / Java 版入门与差异

Playwright 入门教程

Java 版入门与差异

本教程共 59 篇 · 第 59 篇 · 更新于 2026-08-04 · 约 10 分钟阅读

PlaywrightJavaJUnitMavenGradle同步API

59. Java 版入门与差异

本节目标:在 Maven 或 Gradle 项目里装好 Playwright,用 JUnit 5 跑通第一个测试。

Java 版是四种绑定里最「传统」的一个:只有同步 API,没有 await

写起来一行是一行,像普通 Java 代码,反倒是最好上手的。

加依赖

Maven 项目在 pom.xml 里加:

<dependency>
  <groupId>com.microsoft.playwright</groupId>
  <artifactId>playwright</artifactId>
  <version>1.61.0</version>
</dependency>

Gradle 项目在 build.gradle 里加:

dependencies {
    implementation 'com.microsoft.playwright:playwright:1.61.0'
}
Note

Java 版的发布节奏比 Node.js 版慢半拍,版本号也不一定跟主线对齐。撰写本书时 Maven Central 上 com.microsoft.playwright:playwright 的最新版本是 1.61.0,1.62.x 还没发布,所以上面写的是 1.61.0。你动手时先去 Maven Central 搜一下这个坐标,用当时的最新可用版本。

Java 要求 JDK 11 或以上。用 JUnit 5 集成的话,还要额外引入 junit-jupiter 测试依赖。

装浏览器

Java 版没有独立的 playwright 命令,得通过构建工具调用内置 CLI。

mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="install"

这条命令有点长,建议存成脚本。它做的事跟其他语言的 playwright install 一样:下载三套浏览器二进制。

同一个 CLI 也能录制脚本:

mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="codegen playwright.dev"

生成的代码就是 Java 写法,可以直接粘进测试类改。

第一个脚本

先看不带测试框架的裸写法,理解生命周期。

import com.microsoft.playwright.*;

public class App {
    public static void main(String[] args) {
        try (Playwright playwright = Playwright.create()) {
            Browser browser = playwright.chromium().launch();
            Page page = browser.newPage();
            page.navigate("https://playwright.dev");
            System.out.println(page.title());
        }
    }
}

三个细节值得说:

  1. Playwright.create() 启动驱动进程,用 try-with-resources 包住,退出时自动关闭。
  2. 打开网址的方法叫 navigate不叫 goto。因为 goto 是 Java 保留字,不能当方法名。
  3. 全程没有 await。每个调用都是阻塞的,返回时动作已经做完。

想看见浏览器界面,启动时传选项:

Browser browser = playwright.chromium().launch(
    new BrowserType.LaunchOptions().setHeadless(false).setSlowMo(500));

JUnit 5 集成

真正写测试时,别自己管 PlaywrightBrowser。官方提供了 @UsePlaywright 注解,帮你全包了。

import com.microsoft.playwright.Page;
import com.microsoft.playwright.junit.UsePlaywright;
import com.microsoft.playwright.options.AriaRole;
import org.junit.jupiter.api.Test;

import java.util.regex.Pattern;

import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

@UsePlaywright
public class ExampleTest {

    @Test
    void hasTitle(Page page) {
        page.navigate("https://playwright.dev");
        assertThat(page).hasTitle(Pattern.compile("Playwright"));
    }

    @Test
    void getStartedLink(Page page) {
        page.navigate("https://playwright.dev");
        page.getByRole(AriaRole.LINK, new Page.GetByRoleOptions().setName("Get started")).click();
        assertThat(page.getByRole(AriaRole.HEADING,
            new Page.GetByRoleOptions().setName("Installation"))).isVisible();
    }
}

关键在于 Page page 这个方法参数。类上标了 @UsePlaywright,JUnit 就会自动注入。

每个测试方法拿到全新的 Page 和浏览器上下文,彼此隔离。浏览器实例在多个测试间复用,省启动开销。

能注入的类型有这些:

参数类型作用
Page页面,最常用
BrowserContext上下文,需要开多页面时用
Browser浏览器实例
Playwright驱动入口
APIRequestContext做接口测试用

需要哪个就往参数里写哪个,不需要的不写。

Tip

@UsePlaywright 也能标在测试类的父类上。团队里抽一个 BaseTest,所有测试类继承它,注解只写一次。

定制启动选项

想改无头模式、浏览器通道、基础地址,写一个 OptionsFactory 实现类。

import com.microsoft.playwright.Browser;
import com.microsoft.playwright.junit.Options;
import com.microsoft.playwright.junit.OptionsFactory;

public class MyOptions implements OptionsFactory {
    @Override
    public Options getOptions() {
        return new Options()
            .setHeadless(false)
            .setChannel("chrome")
            .setContextOptions(new Browser.NewContextOptions()
                .setBaseURL("https://playwright.dev")
                .setViewportSize(1440, 900));
    }
}

然后把类名传给注解:

@UsePlaywright(MyOptions.class)
public class ExampleTest {
    // ...
}

也可以在这里开 trace 记录:.setTrace(Options.Trace.RETAIN_ON_FAILURE)。失败时才留追踪文件,磁盘不容易爆。

断言写法

Java 版的 Web 优先断言在 PlaywrightAssertions 类里,静态导入后用 assertThat

import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

assertThat(page.getByTestId("status")).hasText("成功");
assertThat(page.getByRole(AriaRole.BUTTON)).isEnabled();
assertThat(page).hasURL(Pattern.compile(".*dashboard"));

名字虽然跟 AssertJ 的 assertThat 撞了,性质完全不同:这套断言会自动重试,等到条件成立或超时。

别用 JUnit 的 Assertions.assertEquals 判断页面状态。它只看一瞬间,页面没渲染完就红了。

想改单条断言的超时:

assertThat(locator).isVisible(new LocatorAssertions.IsVisibleOptions().setTimeout(10000));

命名与传参差异

Java 版的差异集中在三点。

方法名驼峰命名,跟 TS 版基本一致:getByRoleallTextContentswaitFor

选项用链式 setter,不是对象字面量:

// TS 写法:page.goto(url, { waitUntil: 'networkidle' })
page.navigate("https://playwright.dev",
    new Page.NavigateOptions().setWaitUntil(WaitUntilState.NETWORKIDLE));

// TS 写法:page.getByRole('button', { name: '登录' })
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("登录"));

选项类是内部类,名字规律是「所属类 + 方法名 + Options」。写 Page.NavigateOptionsLocator.ClickOptions,IDE 会自动补全。

角色用大写枚举AriaRole.BUTTONAriaRole.HEADINGAriaRole.LINK。这跟 C# 的 AriaRole.Button 只差大小写。

线程安全与并行

这条是 Java 版特有的坑,务必记住。

Warning

Playwright 的对象不是线程安全的。同一个 Page 不能被多个线程同时操作。

正确做法是每个线程创建自己的 Playwright 实例。用 @UsePlaywright 的话,这件事框架已经帮你处理了,直接开并行就行。

JUnit 5 开并行,在 src/test/resources/junit-platform.properties 里配:

junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.config.strategy = fixed
junit.jupiter.execution.parallel.config.fixed.parallelism = 4

并发度按 CPU 核数定。开太大只会互相抢资源。

TestNG 也能用

官方对 Java 不锁死测试框架,TestNG 一样跑得起来。只是没有 @UsePlaywright 这种现成注解。

用 TestNG 的话,自己写 @BeforeMethod / @AfterMethod 管理 PlaywrightPage 的创建销毁。代码多几行,逻辑不复杂。

没有历史包袱就用 JUnit 5。官方注解省事,出问题也好查资料。

新手常踩的两个坑

第一个:自己 new Playwright 又忘了关。 不用 @UsePlaywright 时,Playwright.create() 会拉起一个 Node 驱动进程。忘了关,进程就一直挂着,跑几十个测试后机器内存吃满。

解法是永远用 try-with-resources 包住:

try (Playwright playwright = Playwright.create()) {
    // 用完自动关闭驱动进程
}

第二个:把 Page 存成静态字段共享。 看起来能省创建开销,实际会让测试互相污染,并行时还会因为线程不安全直接崩。

每个测试拿自己的 Page,这是底线。@UsePlaywright 默认就是这个行为,别自己改回去。

跟 TS 版的对照速查

拿 TS 文档翻译成 Java,照这张表改。

TypeScriptJava
page.goto(url)page.navigate(url)
page.getByText('登录')page.getByText("登录")
locator.click()locator.click()
expect(l).toHaveText('x')assertThat(l).hasText("x")
{ timeout: 5000 }new Locator.ClickOptions().setTimeout(5000)
test.beforeEach@BeforeEach

断言方法名去掉了 to 前缀:toHaveTexthasTexttoBeVisibleisVisible。这是 Java 断言库的惯例。

小结

Maven 加 com.microsoft.playwright:playwright,版本请以当时 Maven Central 最新可用版本为准(撰写本书时最新为 1.61.0)。

浏览器靠 mvn exec:java 调 CLI 安装,命令长,存成脚本。

Java 只有同步 API,没有 await;打开网址的方法叫 navigate

JUnit 5 用 @UsePlaywright 注解,把 Page 写进测试方法参数就能自动注入。

断言用 PlaywrightAssertions.assertThat,会自动重试,别混用 JUnit 原生断言判断页面。

Playwright 对象不是线程安全的,并行时确保每个线程独立持有实例。

上一篇
.NET 版入门与差异
下一篇
已经是最后一篇啦