这是一个基于 Playwright + NUnit 的自动化测试框架,具有以下特点:
- ✅ 配置驱动 - 通过配置文件统一管理测试参数
- ✅ 简洁易用 - 提供 TestBase 基类简化测试代码
- ✅ 功能完整 - 支持截图、视频录制、多浏览器
- ✅ 易于维护 - 代码结构清晰,遵循最佳实践
PlaywrightAutomation/
├── PlaywrightTests/
│ ├── Config/ # 配置文件
│ │ ├── appsettings.json # 主配置文件
│ │ ├── appsettings.Development.json
│ │ └── appsettings.Production.json
│ ├── Data/ # 测试数据
│ │ ├── testdata.json
│ │ ├── users.csv
│ │ └── products.xml
│ ├── Models/ # 数据模型
│ │ ├── User.cs
│ │ ├── Product.cs
│ │ └── TestData.cs
│ ├── Pages/ # Page Object 页面对象
│ │ ├── BasePage.cs
│ │ ├── LoginPage.cs
│ │ ├── DashboardPage.cs
│ │ └── ProductPage.cs
│ ├── Tests/ # 测试用例
│ │ ├── BaiduSearchTests_Optimized.cs # 优化版测试
│ │ ├── LoginTests.cs
│ │ └── ...
│ ├── Utilities/ # 工具类
│ │ ├── ConfigManager.cs # 配置管理器 ⭐
│ │ ├── BrowserFactory.cs # 浏览器工厂 ⭐
│ │ └── ScreenshotHelper.cs
│ ├── Reports/ # 测试报告
│ │ ├── screenshots/ # 截图
│ │ ├── videos/ # 视频
│ │ └── logs/ # 日志
│ ├── TestBase.cs # 测试基类 ⭐
│ └── PlaywrightTests.csproj
└── PlaywrightAutomation.sln
PlaywrightTests/Config/appsettings.json
{
"TestSettings": {
"Browser": {
"Type": "Chromium", // Chromium, Firefox, WebKit
"Headless": false, // 是否无头模式
"SlowMo": 100, // 操作延迟(毫秒)
"ViewportWidth": 1920, // 视口宽度
"ViewportHeight": 1080 // 视口高度
}
}
}配置说明:
Type: 浏览器类型Chromium- 类Chrome浏览器(推荐)Firefox- Firefox浏览器WebKit- 类Safari浏览器
Headless:false- 显示浏览器窗口(调试用)true- 后台运行(CI/CD用)
SlowMo: 每个操作之间的延迟时间,便于观察
{
"Screenshots": {
"Enabled": true, // 是否启用截图
"OnFailure": true, // 失败时自动截图
"Directory": "Reports/screenshots/"
}
}{
"Videos": {
"Enabled": false, // 是否启用视频录制
"Directory": "Reports/videos/"
}
}{
"TestData": {
"DefaultUser": {
"Username": "testuser",
"Password": "Password123!"
},
"AdminUser": {
"Username": "admin",
"Password": "Admin123!"
}
}
}通过环境变量 DOTNET_ENVIRONMENT 切换配置:
# 开发环境(默认)
$env:DOTNET_ENVIRONMENT = "Development"
# 生产环境
$env:DOTNET_ENVIRONMENT = "Production"cd f:\desktop\PlaywrightAutomation
dotnet restorepwsh PlaywrightTests/bin/Debug/net8.0/playwright.ps1 installdotnet build# 运行所有测试
dotnet test
# 运行优化版百度搜索测试
dotnet test --filter "FullyQualifiedName~BaiduSearchTests_Optimized"位置: Utilities/ConfigManager.cs
功能: 统一管理所有配置项,单例模式
使用方式:
var config = ConfigManager.Instance;
// 获取浏览器配置
var browserType = config.BrowserType;
var headless = config.Headless;
var slowMo = config.SlowMo;
// 获取截图配置
var screenshotsEnabled = config.ScreenshotsEnabled;
var screenshotDir = config.ScreenshotsDirectory;
// 获取测试数据
var username = config.DefaultUsername;
var password = config.DefaultPassword;位置: Utilities/BrowserFactory.cs
功能: 创建和配置浏览器实例
使用方式:
var factory = new BrowserFactory();
// 使用配置文件启动浏览器(推荐)
var browser = await factory.LaunchBrowserAsync();
// 手动指定参数启动浏览器
var browser = await factory.LaunchBrowserAsync(
BrowserFactory.BrowserType.Chromium,
headless: false,
slowMo: 500
);
// 创建浏览器上下文
var context = await factory.CreateContextAsync(browser);
// 创建页面
var page = await context.NewPageAsync();位置: TestBase.cs
功能: 提供统一的浏览器初始化、资源清理和常用方法
继承使用:
[TestFixture]
public class MyTests : TestBase
{
[Test]
public async Task Test_Example()
{
// 浏览器已自动初始化,直接使用 Page
await NavigateToAsync("https://www.baidu.com");
await FillAsync("#kw", "测试");
await PressKeyAsync("Enter");
var url = GetCurrentUrl();
Assert.That(url, Does.Contain("baidu.com/s?"));
// 资源会自动清理
}
}提供的方法:
NavigateToAsync(url)- 导航到URLWaitAsync(milliseconds)- 等待指定时间TakeScreenshotAsync(name)- 截图FillAsync(selector, value)- 填充输入框ClickAsync(selector)- 点击元素PressKeyAsync(key)- 按键GetCurrentUrl()- 获取当前URLReloadAsync()- 刷新页面WaitForElementAsync(selector)- 等待元素可见
优点: 代码简洁、自动管理资源、失败自动截图
using NUnit.Framework;
namespace PlaywrightTests.Tests;
[TestFixture]
public class MyTests : TestBase
{
[Test]
[Category("Search")]
[Description("百度搜索测试")]
public async Task Test_BaiduSearch()
{
// 1. 打开百度
await NavigateToAsync("https://www.baidu.com");
await WaitAsync(2000);
// 2. 搜索
await FillAsync("#kw", "Playwright");
await PressKeyAsync("Enter");
await WaitAsync(3000);
// 3. 验证
var url = GetCurrentUrl();
Assert.That(url, Does.Contain("baidu.com/s?"));
Console.WriteLine("✅ 测试通过");
// 4. 截图
await TakeScreenshotAsync("search_result");
}
}[TestFixture]
public class CustomTests
{
private BrowserFactory? _factory;
private IBrowser? _browser;
private IPage? _page;
[SetUp]
public async Task Setup()
{
_factory = new BrowserFactory();
_browser = await _factory.LaunchBrowserAsync();
var context = await _factory.CreateContextAsync(_browser);
_page = await context.NewPageAsync();
}
[TearDown]
public async Task Teardown()
{
if (_page != null) await _page.CloseAsync();
if (_browser != null) await _browser.CloseAsync();
_factory?.Dispose();
}
[Test]
public async Task Test_Custom()
{
await _page!.GotoAsync("https://example.com");
// 自定义测试逻辑
}
}# 运行所有测试
dotnet test
# 运行特定类别的测试
dotnet test --filter "Category=Baidu"
dotnet test --filter "Category=Search"
# 运行特定测试
dotnet test --filter "FullyQualifiedName~Test_BaiduSearch_BasicFlow"
# 带详细输出
dotnet test --logger "console;verbosity=detailed"
# 运行优化版测试
dotnet test --filter "FullyQualifiedName~BaiduSearchTests_Optimized"测试运行后会生成:
- 控制台输出 - 实时查看测试进度
- 截图 -
Reports/screenshots/目录 - 视频 -
Reports/videos/目录(如启用) - 失败截图 - 自动保存,文件名前缀
FAILED_
[TestFixture]
public class BaiduSearchTests_Headed
{
private IPlaywright? _playwright;
private IBrowser? _browser;
private IPage? _page;
[SetUp]
public async Task Setup()
{
_playwright = await Playwright.CreateAsync();
_browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
Headless = false,
SlowMo = 500,
Args = new[] { "--start-maximized" }
});
var context = await _browser.NewContextAsync(new BrowserNewContextOptions
{
ViewportSize = ViewportSize.NoViewport
});
_page = await context.NewPageAsync();
}
[TearDown]
public async Task Teardown()
{
await Task.Delay(2000);
if (_page != null) await _page.CloseAsync();
if (_browser != null) await _browser.CloseAsync();
_playwright?.Dispose();
}
[Test]
public async Task Test_Search()
{
await _page!.GotoAsync("https://www.baidu.com");
await Task.Delay(2000);
await _page.Locator("#kw").FillAsync("抖音", new() { Force = true });
await Task.Delay(1000);
await _page.Keyboard.PressAsync("Enter");
await Task.Delay(3000);
// ... 更多重复代码
}
}[TestFixture]
public class BaiduSearchTests_Optimized : TestBase
{
private const string BaiduUrl = "https://www.baidu.com";
[Test]
[Category("Baidu")]
[Description("百度搜索 - 基础搜索流程")]
public async Task Test_BaiduSearch_BasicFlow()
{
await NavigateToAsync(BaiduUrl);
await WaitAsync(2000);
await FillAsync("#kw", "抖音");
await PressKeyAsync("Enter");
await WaitAsync(3000);
var url = GetCurrentUrl();
Assert.That(url, Does.Contain("baidu.com/s?"));
await TakeScreenshotAsync("baidu_search_results");
}
}- 代码量减少 54% - 从187行减少到85行
- 可读性提升 - 方法命名语义化
- 维护性提升 - 统一在基类修改
- 配置驱动 - 无需硬编码参数
- 自动截图 - 失败时自动截图
- 资源管理 - 自动清理,防止泄漏
A: 修改 appsettings.json 中的配置:
{
"TestSettings": {
"Browser": {
"Type": "Firefox" // 改为 Firefox 或 WebKit
}
}
}A: 修改 Headless 配置:
{
"Browser": {
"Headless": false // false-显示窗口, true-隐藏窗口
}
}A: 修改 SlowMo 配置(单位:毫秒):
{
"Browser": {
"SlowMo": 500 // 每个操作延迟500ms
}
}A: 默认保存在:
PlaywrightTests/bin/Debug/net8.0/Reports/screenshots/
可在配置文件中修改路径。
A: 修改配置并确保录制目录存在:
{
"Videos": {
"Enabled": true,
"Directory": "Reports/videos/"
}
}A: 使用 TestBase 基类会自动处理,确保配置已启用:
{
"Screenshots": {
"OnFailure": true
}
}A: 创建环境特定的配置文件,然后设置环境变量:
# Windows PowerShell
$env:DOTNET_ENVIRONMENT = "Production"
# 然后运行测试
dotnet testA: 确保已安装必要的 NuGet 包:
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.Configuration.EnvironmentVariablesdotnet test --filter "FullyQualifiedName~Test_BaiduSearch_BasicFlow"输出:
✅ 浏览器已启动 (Chromium, Headless: False)
📍 已导航到: https://www.baidu.com
✅ 搜索成功
📸 截图已保存: Reports/screenshots/baidu_search_results_20251220_135007.png
✅ 浏览器已关闭
测试摘要: 总计: 1, 失败: 0, 成功: 1
dotnet test --filter "FullyQualifiedName~Test_BaiduSearch_MultipleKeywords"输出:
🔍 搜索关键词: C#
📸 截图已保存: Reports/screenshots/search_C#_20251220_135020.png
🔍 搜索关键词: Playwright
📸 截图已保存: Reports/screenshots/search_Playwright_20251220_135025.png
🔍 搜索关键词: 自动化测试
📸 截图已保存: Reports/screenshots/search_自动化测试_20251220_135030.png
✅ 所有关键词搜索完成
- 简化代码
- 统一资源管理
- 自动失败截图
- 不要硬编码参数
- 便于环境切换
- 便于团队协作
- 优先使用
WaitForElementAsync(selector)等待元素 - 避免过多使用
Task.Delay()
- 关键步骤添加日志
- 失败时自动截图
- 方便问题排查
- 将页面元素和操作封装到 Page 类
- 提高可维护性
- 便于复用
- ✅ 新增 ConfigManager 配置管理器
- ✅ 优化 BrowserFactory 支持配置驱动
- ✅ 新增 TestBase 基类简化测试代码
- ✅ 创建优化版测试示例
- ✅ 完善项目文档
- ✅ 项目初始化
- ✅ 基础框架搭建
- ✅ 百度搜索示例测试
如有问题或建议,欢迎反馈!
Happy Testing! 🎉