首页
/ Playwright .NET 库模式实战:从控制台项目、Web-First 断言到跨平台 Driver 打包

Playwright .NET 库模式实战:从控制台项目、Web-First 断言到跨平台 Driver 打包

2026-09-06 13:19:52作者:姚月梅Lane

本篇技术指南围绕 Playwright 官方文档中的 .NET「Library(库)」用法展开,讲解如何在不依赖 MSTest、NUnit、xUnit 等测试框架基类的情况下,以 Microsoft.Playwright NuGet 包为核心编写独立自动化脚本。读完本文,你将掌握:完整的 .NET 控制台项目搭建与浏览器安装流程、页面导航与截图的最小可运行示例、headless/slowMo 启动参数、库模式下 Web-First 自动重试断言的用法,以及通过 PlaywrightPlatform 属性为多平台打包 Driver 的方法。

什么是 Playwright 的 .NET 库模式

Playwright for .NET 有两种主要使用方式:

  1. 测试框架模式:使用 Playwright 为 MSTest、NUnit、xUnit 或 xUnit v3 提供的基类(PageTestContextTest 等),详见 docs/src/test-runners-csharp.md
  2. 库模式(本文主题):直接把 Microsoft.Playwright 当作普通库引入,在自己的应用代码或其他测试运行器中手动管理 PlaywrightBrowserPage 的生命周期。

如果你的场景是开发一个利用 Playwright 能力的应用程序(例如爬取、截图服务、CI 中的自定义自动化步骤),或者你的测试运行器与 Playwright 官方基类不匹配,那么库模式是合适的选择。库模式的代价是:浏览器与上下文的创建、复用和清理需要你自己负责,好在 API 语义与官方测试框架完全一致。

快速创建项目并安装浏览器

库模式的起点是一个非常普通的 .NET 控制台项目。按官方文档 docs/src/library-csharp.md 的步骤操作:

# Create project
dotnet new console -n PlaywrightDemo
cd PlaywrightDemo

# Add project dependency
dotnet add package Microsoft.Playwright
# Build the project
dotnet build
# Install required browsers - replace netX with actual output folder name, e.g. net8.0.
pwsh bin/Debug/netX/playwright.ps1 install

几个关键细节需要注意:

  • netX 是占位符pwsh bin/Debug/netX/playwright.ps1 install 中的 netX 需要替换为你项目实际的输出目录名,例如 net8.0。构建完成后可以在 bin/Debug/net8.0/ 下看到随包分发的 playwright.ps1 安装脚本。
  • PowerShell 版本问题:如果 pwsh 命令抛出 TypeNotFound 错误,说明你的 PowerShell 版本过旧,执行以下命令升级:
dotnet tool update --global PowerShell
  • playwright.ps1 install 从哪里来:这一约定在 Playwright 核心代码中有明确印证。从源码结构看,packages/playwright-core/src/server/registry/index.ts 中的 buildPlaywrightCLICommand 函数按 SDK 语言生成了不同的 CLI 安装命令,其中 C# 对应的正是 pwsh bin/Debug/netX/playwright.ps1 <parameters>;CLI 帮助文本生成逻辑 packages/playwright-core/src/cli/program.ts 也使用同一约定。也就是说,.NET 场景下「用构建产物里的脚本装浏览器」是 Playwright 工具链设计好的标准路径,与 JavaScript 生态的 npx playwright install 一一对应。

该脚本会下载与已安装 SDK 版本匹配的浏览器二进制到本地浏览器缓存目录,之后即可离线启动。

最小示例:导航并截图

创建 Program.cs,用 Chromium 打开指定页面并保存截图——这是官方文档给出的标准最小示例,可直接复制运行:

using Microsoft.Playwright;

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await page.GotoAsync("https://playwright.dev/dotnet");
await page.ScreenshotAsync(new()
{
    Path = "screenshot.png"
});

代码要点:

  • Playwright.CreateAsync() 是库模式的入口,它会启动 Playwright 驱动进程并返回句柄。用 using 声明,程序退出时自动释放驱动;
  • playwright.Chromium.LaunchAsync() 启动 Chromium 内核浏览器。同样的 API 还有 playwright.Firefoxplaywright.WebKit,三者共享同一套 API,这正是 Playwright「一套 API 驱动三种引擎」的核心卖点;
  • browser.NewPageAsync() 创建一个全新上下文(BrowserContext)加页面。注意:上下文与页面不是 IAsyncDisposable,由 Browser 释放时一并清理,因此这里没有对其使用 await using
  • page.ScreenshotAsync(new() { Path = "screenshot.png" }) 使用 C# 9 的 target-typed new 省略写法,等价于传入一个 PageScreenshotOptions 对象,也可按需追加 FullPageType 等参数。

然后运行:

dotnet run

执行完毕后当前目录会生成 screenshot.png

有头模式与 Slow Mo

默认情况下 Playwright 以 headless(无头)模式运行浏览器。若要看到浏览器界面用于调试,将 BrowserType.launchheadless 选项设为 false;还可以用 slowMo 参数人为放慢操作节奏,官方文档建议在调试场景下配合 docs/src/debug.md 一起使用:

await using var browser = await playwright.Firefox.LaunchAsync(new()
{
    Headless = false,
    SlowMo = 50,
});

SlowMo = 50 表示每个 Playwright 操作之间额外插入 50 毫秒延迟,方便肉眼观察页面变化。这个参数并非只存在于文档:从源码结构看,packages/playwright-core/src/client/browserType.tsLaunchAsync 的启动参数会把 slowMo: params.slowMo 原样传递给驱动端,因此 .NET、Node、Python 各 SDK 的 slowMo 行为是一致的。

库模式中使用 Web-First 断言

即使不使用 Playwright 官方测试基类,你依然可以使用它的 Web-First 断言。这类断言的核心特性是自动重试:Playwright 会反复重新获取元素并检查条件,直到条件满足或超时(例如等待某个链接出现特定文案)。

官方文档给出的完整示例:

using Microsoft.Playwright;
using static Microsoft.Playwright.Assertions;

// Change the default 5 seconds timeout if you'd like.
SetDefaultExpectTimeout(10_000);

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await page.GotoAsync("https://playwright.dev/dotnet");
await Expect(page.GetByRole(AriaRole.Link, new() { Name = "Get started" })).ToBeVisibleAsync();

要点解析:

  • using static Microsoft.Playwright.Assertions; 静态导入后,Expect(...)SetDefaultExpectTimeout(...) 直接可用;
  • 默认断言超时是 5 秒。这一点在 docs/src/test-assertions-csharp-java-python.md 中有明确说明("By default, the timeout for assertions is 5 seconds")。示例中调用 SetDefaultExpectTimeout(10_000) 把全局断言超时改为 10 秒,适用于页面加载较慢的场景;
  • page.GetByRole(AriaRole.Link, new() { Name = "Get started" }) 是按 ARIA 角色 + 可访问名称定位元素的推荐方式,比脆弱的 CSS/XPath 选择器更抗改版;
  • ToBeVisibleAsync() 属于可自动重试的 Locator 断言族(toBeVisibletoHaveTexttoHaveValue 等)。与测试框架模式不同的是,库模式下断言失败会直接抛出 TimeoutError 异常,由你自己的代码决定如何捕获与处理。

为不同平台打包 Driver

Microsoft.Playwright 包内置 Node.js 驱动(Playwright 的 .NET SDK 本质上是对驱动进程的消息转发)。默认情况下,发布(publish)时只会打包 .NET publish 目标运行平台对应的那份 Driver。如果你希望产物能在其他操作系统上运行(例如在 Linux CI 上发布、产物分发到 Windows 客户端),可以在项目文件(.csproj)中通过 PlaywrightPlatform MSBuild 属性覆盖默认行为,取值支持 allnonelinuxwinosx

<PropertyGroup>
  <PlaywrightPlatform>all</PlaywrightPlatform>
</PropertyGroup>

也可以只选择特定平台的组合,用分号分隔:

<PropertyGroup>
  <PlaywrightPlatform>osx;linux</PlaywrightPlatform>
</PropertyGroup>
  • all:三种平台的 Driver 全部随产物发布,体积最大但通用性最强;
  • none:不打包任何 Driver,适合你确定运行环境已具备驱动的场景;
  • osx;linux:只携带 macOS 与 Linux 的 Driver,产物体积与兼容性折中。

需要注意的适用前提:PlaywrightPlatform 影响的是 publish 时 Driver 的打包范围,而浏览器二进制仍需在各运行环境上通过 playwright.ps1 install(或等价方式)单独安装,二者不要混淆。

小结与延伸阅读

本文完整覆盖了 Playwright .NET 库模式的核心链路:dotnet add package Microsoft.Playwright 引入依赖 → pwsh bin/Debug/netX/playwright.ps1 install 安装浏览器 → 用 Playwright.CreateAsync() 手工管理浏览器生命周期 → SetDefaultExpectTimeout + Expect(...) 获得自动重试断言 → 用 PlaywrightPlatform 控制跨平台 Driver 打包。相关仓库资料可供继续深入:

登录后查看全文
热门项目推荐
相关项目推荐