playwright是c#端到端测试最轻量可靠的选择,原生支持多浏览器、自动下载二进制、无需webdriver管理器;需为每个测试独占ibrowsercontext,正确使用waitforurlasync、isvisibleasync等断言,并在失败时条件截图。

Playwright 是目前 C# 端到端测试最轻量、最可靠的选择,它原生支持 Chromium/Firefox/WebKit,且无需 Selenium WebDriver 管理器。直接用 Microsoft.Playwright NuGet 包 + dotnet test 就能跑真实浏览器流程,比 Selenium 稳定、比 Puppeteer.NET 更易维护。
安装 Playwright 并初始化浏览器实例
不装全局驱动、不配环境变量——Playwright 会自动下载对应浏览器二进制。关键就两步:
- 执行
dotnet add package Microsoft.Playwright - 在测试类的
[TestInitialize]或[SetUp](xUnit 用IAsyncLifetime)里调用await Playwright.CreateAsync(),再用browser.NewContextAsync()
别直接复用 browser 实例跑多个测试:每个测试必须独占 IBrowserContext,否则 cookie、localStorage、网络拦截会互相污染。错误写法:browser.NewPageAsync() 直接挂到类字段上;正确做法是每次测试都新建 context + page。
模拟登录 + 跨页面跳转的典型断言写法
端到端测试不是“点完就完”,重点是验证状态是否真正生效。比如登录后跳转到仪表盘,不能只断言 URL,还要查 DOM 元素或 API 响应:
- 用
page.WaitForURLAsync("/dashboard")等跳转完成,但得配合超时(默认 30s,建议显式设为new PageWaitForURLOptions { Timeout = 10000 }) - 登录表单提交后,优先断言
await page.GetByText("Welcome,").IsVisibleAsync(),而不是Assert.Contains("Welcome", page.ContentAsync().Result)(后者可能拿到未渲染完的 HTML) - 需要验证后端响应?用
page.RouteAsync("**/api/profile", route => route.FulfillAsync(new() { Status = 200, ContentType = "application/json", BodyString = "{\"name\":\"Alice\"}" }))拦截并伪造,避免依赖真实服务
截图与失败诊断:为什么 page.ScreenshotAsync() 必须加条件
无脑截图会拖慢所有测试、撑爆磁盘。只在失败时截,且必须限定范围:
- 在
try/catch的catch块里调用await page.ScreenshotAsync(new() { Path = $"fail-{DateTime.Now:HHmmss}.png" }) - 别截全屏(
FullPage = true),默认只截可视区;若需完整页,先await page.EvaluateAsync("window.scrollTo(0, document.body.scrollHeight)")再截 - 截图前加
await page.WaitForLoadStateAsync(LoadState.NetworkIdle),否则可能截到 loading 状态的空白页
MSTest/xUnit 与 Playwright 的生命周期对齐问题
Playwright 的 IBrowser 和 IBrowserContext 是异步资源,但 MSTest 的 [TestCleanup] 不支持 async。硬写 context.CloseAsync().Wait() 会死锁(尤其在 .NET 6+ 默认线程池调度下)。
解法只有两个:
- xUnit 用户:实现
IAsyncLifetime,把DisposeAsync交给框架调度 - MSTest 用户:改用
[ClassInitialize]/[ClassCleanup]配合Task.Run(() => browser.CloseAsync()).Wait()(仅限 class 级共享 browser,不推荐单测粒度) - 更稳妥的做法:彻底放弃 MSTest,换 xUnit —— 它对 async 测试生命周期的支持是开箱即用的
真正容易被忽略的,是 Playwright 的 browser 实例本身不能跨进程复用。CI 环境里如果多个 test assembly 并行跑,各自 new 一个 Playwright.CreateAsync() 是安全的;但若试图在不同项目间共享 static browser,会触发 System.InvalidOperationException: Browser has been closed。










