使用Playwright C#的OneTimeSetUp时Page出现空引用异常
问题原因
PageTest基类的Page属性是在每个测试的[SetUp]阶段才完成初始化的,而[OneTimeSetUp]是在测试Fixture初始化时执行,这个时机早于Page的创建流程,所以直接访问Page会抛出空引用异常。
解决方案
要在[OneTimeSetUp]中完成登录并存储认证状态,需要手动管理Playwright的Browser、Context和Page实例,而非依赖PageTest提供的属性。具体实现如下:
- 在Fixture类中声明Browser、IBrowserContext和IPage私有字段
- 在[OneTimeSetUp]中初始化Playwright、Browser、Context和Page,完成登录并保存认证状态
- 在[OneTimeTearDown]中清理资源,按需执行登出并销毁Context和Browser
- 测试方法可直接使用PageTest提供的Page属性,它会自动加载已保存的认证状态
修改后的代码示例:
using Microsoft.Playwright; using Microsoft.Playwright.NUnit; using System; namespace PlaywrightTests { [Parallelizable(ParallelScope.Fixtures)] public class Tests1V2 : PageTest { private string site = "https://google.co.uk/"; private IBrowser? _browser; private IBrowserContext? _context; private IPage? _oneTimePage; [OneTimeSetUp] public async Task OneTimeSetUp() { // 初始化Playwright并启动浏览器 var playwright = await Playwright.CreateAsync(); _browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = true // 根据测试需求调整是否启用无头模式 }); // 创建上下文并初始化页面 _context = await _browser.NewContextAsync(); _oneTimePage = await _context.NewPageAsync(); // 执行登录流程(替换为你的实际登录逻辑) await _oneTimePage.GotoAsync(site); // 示例:输入账号密码、点击登录按钮 // await _oneTimePage.FillAsync("#username", "your-account"); // await _oneTimePage.FillAsync("#password", "your-password"); // await _oneTimePage.ClickAsync("#submit-login"); // 保存认证状态到本地文件 await _context.StorageStateAsync(new BrowserContextStorageStateOptions { Path = "state.json" }); } [OneTimeTearDown] public async Task OneTimeTearDown() { // 清理资源,按需执行登出操作 if (_oneTimePage != null) { // await _oneTimePage.GotoAsync("/logout"); await _oneTimePage.CloseAsync(); } if (_context != null) await _context.CloseAsync(); if (_browser != null) await _browser.CloseAsync(); } public override BrowserNewContextOptions ContextOptions() { var contextOptions = new BrowserNewContextOptions(); // 让后续测试的上下文自动加载已保存的认证状态 contextOptions.StorageStatePath = "state.json"; if (Environment.GetEnvironmentVariable("width") != null && int.TryParse(Environment.GetEnvironmentVariable("width"), out int width)) { contextOptions.ViewportSize = new ViewportSize { Width = width, Height = 1080 }; } return contextOptions; } [Test] public async Task AALoginTest1() { // 直接使用PageTest提供的Page属性,已自动携带登录态 await Page.GotoAsync(site); // var mainPage = new MainPage(Page); // var checkContact = await mainPage.checkLoggedIn(); // Assert.IsTrue(checkContact); } } }
关键说明
- 手动创建的
_oneTimePage仅用于执行一次性登录操作,完成后保存认证状态 - 后续测试的Page属性会通过
ContextOptions()中指定的StorageStatePath自动加载登录态,无需重复执行登录流程 - [OneTimeTearDown]中统一清理资源,避免内存泄漏,同时可按需执行登出操作重置状态
内容的提问来源于stack exchange,提问作者user500770
相关产品推荐
相关产品推荐

