当前位置: 首页 > news >正文

ABP VNext + Playwright E2E:前后端一体化自动化测试

ABP VNext + Playwright E2E:前后端一体化自动化测试 🚀


📚 目录

  • ABP VNext + Playwright E2E:前后端一体化自动化测试 🚀
    • 一、引言
      • ✨ TL;DR
      • 📚 背景与动机
    • 二、环境与依赖
    • 三、项目结构示例
    • 四、安装与初始化 Playwright
    • 五、测试基类与数据隔离
      • 1. 自定义 TestWebApplicationFactory 🏭
      • 2. 事务隔离 🌐
    • 六、测试流程图 📝
    • 七、登录流程测试 🔑
    • 八、CRUD 操作与 API 拦截 ✂️
    • 九、并行执行与多环境隔离 ⚙️
    • 十、CI 流水线流程图 🚦
    • 十一、GitHub Actions & 报告集成 🎯
    • 十二、报告与调试 🐞
    • 十三、跨框架复用 🔄


一、引言

✨ TL;DR

  • 🔥 使用 Playwright for .NET + WebApplicationFactory 自动启动后端,实现前后端一体化 E2E 测试
  • 🔒 通过 TransactionScope(指定隔离级别)进行跨 DbContext 事务隔离,测试结束自动回滚
  • ✅ 覆盖登录、CRUD、API 拦截与性能断言,支持多浏览器并行 & 本地/CI 集成
  • 🎥 自动录制失败 视频Trace,并生成 HTML 报告,便于调试与持续集成

📚 背景与动机

在微服务与前后端分离架构下,单元测试难以捕捉 UI 与后端交互、网络请求和路由跳转等真实场景问题。借助 Playwright for .NET 的多内核自动化 + ABP VNext 的模块化后端,我们可以在“关闭真实外部依赖”的隔离环境中,完整验证业务链路,提高测试可信度与效率。


二、环境与依赖

  • .NET SDK:≥ 8.0(ABP VNext)

  • Node.js:≥ 16(Playwright 浏览器内核)

  • NuGet 包

    • Microsoft.Playwright
    • Microsoft.Playwright.Xunit(提供 PageTestPlaywrightFact 等基类)
  • 测试框架:xUnit

  • 浏览器内核:Chromium、Firefox、WebKit


三、项目结构示例

MyApp/
├─ src/
│   └─ MyApp.HttpApi.Host/       # ABP 后端
├─ tests/
│   └─ E2ETests/
│       ├─ E2ETests.csproj       # 测试工程
│       ├─ TestWebApplicationFactory.cs  # 自定义宿主
│       ├─ TestFixture.cs        # 基类:事务隔离、初始化/清理 
│       ├─ LoginTests.cs         # 登录测试
│       ├─ ProductCrudTests.cs   # CRUD 测试
│       └─ playwright.config.js   # Playwright 安装脚本

四、安装与初始化 Playwright

# 进入测试目录,安装浏览器内核(仅一次)
cd tests/E2ETests
npx playwright install# 添加 NuGet 依赖
dotnet add package Microsoft.Playwright
dotnet add package Microsoft.Playwright.Xunit
// tests/E2ETests/playwright.config.js
module.exports = {}; // 如需自定义可在此添加

五、测试基类与数据隔离

1. 自定义 TestWebApplicationFactory 🏭

// TestWebApplicationFactory.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;public class TestWebApplicationFactory : WebApplicationFactory<Program>
{protected override void ConfigureWebHost(IWebHostBuilder builder){builder.ConfigureServices(services =>{// 移除原有 DbContext 注册var descriptor = services.Single(d => d.ServiceType == typeof(DbContextOptions<MyAppDbContext>));services.Remove(descriptor);// 注册测试库连接(可用环境变量动态配置)services.AddDbContext<MyAppDbContext>(options =>options.UseSqlServer("Server=localhost;Database=MyApp_Test;User Id=sa;Password=Your_pwd123;"));});}
}

2. 事务隔离 🌐

// TestFixture.cs
using System.Transactions;
using Microsoft.Playwright.Xunit;public abstract class E2ETestBase : PageTest
{protected TestWebApplicationFactory Factory { get; private set; }protected HttpClient ApiClient { get; private set; }private TransactionScope _txScope;public override async Task OnInitializeAsync(){await base.OnInitializeAsync();   // 启动后端宿主Factory = new TestWebApplicationFactory();ApiClient = Factory.CreateClient();// 开启事务(指定隔离级别为 ReadCommitted)var options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };_txScope = new TransactionScope(TransactionScopeOption.Required, options, TransactionScopeAsyncFlowOption.Enabled);// 种子数据示例using var scope = Factory.Services.CreateScope();var db = scope.ServiceProvider.GetRequiredService<MyAppDbContext>();db.Products.Add(new Product { Name = "SeedProduct", Price = 1.23M });await db.SaveChangesAsync();}public override async Task OnCleanupAsync(){await base.OnCleanupAsync();    // 先让 Playwright 清理_txScope.Dispose();             // 回滚事务Factory.Dispose();              // 释放宿主}
}

💡Tips:并行执行时,可结合 Testcontainers 为每个 worker 动态创建隔离数据库,或在连接字符串中拼接线程 ID。


六、测试流程图 📝

启动测试宿主
预置种子数据
执行登录测试
执行 CRUD 测试
拦截 & 性能断言
回滚事务 & 清理
生成本地报告

七、登录流程测试 🔑

// LoginTests.cs
using Microsoft.Playwright.Xunit;public class LoginTests : E2ETestBase
{[PlaywrightFact(Timeout = 60000, Video = VideoMode.RetainOnFailure, Trace = TraceMode.On)]public async Task Admin_Can_Login_And_See_Homepage(){var baseUrl = Factory.Server.BaseAddress!;await Page.GotoAsync($"{baseUrl}/auth/login");await Page.FillAsync("input[name=\"username\"]", "admin");await Page.FillAsync("input[name=\"password\"]", "123qwe");await Page.ClickAsync("button[type=\"submit\"]");await Page.WaitForURLAsync($"{baseUrl}/");Assert.True(await Page.Locator("text=欢迎, admin").IsVisibleAsync());}
}

八、CRUD 操作与 API 拦截 ✂️

// ProductCrudTests.cs
using System.Diagnostics;
using Microsoft.Playwright.Xunit;public class ProductCrudTests : E2ETestBase
{[PlaywrightFact(Timeout = 60000, Video = VideoMode.RetainOnFailure, Trace = TraceMode.On)]public async Task Perform_Product_CRUD_And_Assert_API_Performance(){var baseUrl = Factory.Server.BaseAddress!;// 拦截 POST 并断言await Page.RouteAsync("**/api/app/products", async route =>{Assert.Equal("POST", route.Request.Method);await route.ContinueAsync();});// 性能断言var sw = Stopwatch.StartNew();await Page.GotoAsync($"{baseUrl}/products");await Page.WaitForResponseAsync("**/api/app/products");sw.Stop();Assert.True(sw.ElapsedMilliseconds < 200, $"API 响应超时:{sw.ElapsedMilliseconds} ms");// 创建await Page.FillAsync("input[name=\"name\"]", "TestProduct");await Page.FillAsync("input[name=\"price\"]", "9.99");await Page.ClickAsync("button[type=\"submit\"]");await Page.WaitForSelectorAsync("text=TestProduct");// 更新await Page.ClickAsync("button.edit-btn");await Page.FillAsync("input[name=\"price\"]", "19.99");await Page.ClickAsync("button.save-btn");await Page.WaitForSelectorAsync("text=19.99");// 删除await Page.ClickAsync("button.delete-btn");await Page.ClickAsync("button.confirm-delete");await Page.WaitForSelectorAsync("text=No products found");}
}

九、并行执行与多环境隔离 ⚙️

// AssemblyInfo.cs
using Xunit;[assembly: CollectionBehavior(DisableTestParallelization = false, MaxParallelThreads = 4)]

💡Tips:可通过环境变量或 Testcontainers 为每个 worker 动态生成不同的数据库实例,彻底隔离竞态。


十、CI 流水线流程图 🚦

Checkout 代码
Setup .NET & Node
Install Playwright Browsers
Build 项目
Run E2E Tests
生成 HTML 报告
上传 Artifacts

十一、GitHub Actions & 报告集成 🎯

name: E2E Testson: [push, pull_request]jobs:e2e:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup .NET & Node.jsuses: actions/setup-dotnet@v3with:dotnet-version: '8.0'- uses: actions/setup-node@v3with:node-version: '16'- name: Install Playwright Browsersworking-directory: tests/E2ETestsrun: npx playwright install --with-deps- name: Build Backend & Testsrun: dotnet build --configuration Release- name: Run E2E Testsworking-directory: tests/E2ETestsrun: |dotnet test --logger "trx;LogFileName=TestResults.trx" --results-directory ./results- name: Generate Playwright HTML Reportrun: |npm install -g report-generatorreportgenerator -reports:tests/E2ETests/results/TestResults.trx -targetdir:tests/E2ETests/results/html- name: Upload Test Artifactsuses: actions/upload-artifact@v3with:name: e2e-test-reportpath: |tests/E2ETests/results/htmltests/E2ETests/results/TestResults.trx

十二、报告与调试 🐞

  • 视频 & Trace:失败用例自动保留在 TestResults,可通过 npx playwright show-trace trace.zip 可视化
  • 日志调试:本地运行时设置 DEBUG=pw:api,打印 Playwright 与浏览器交互细节

十三、跨框架复用 🔄

public async Task LoginAsAsync(string user, string pwd)
{await Page.GotoAsync($"{BaseUrl}/auth/login");await Page.FillAsync("input[name=\"username\"]", user);await Page.FillAsync("input[name=\"password\"]", pwd);await Page.ClickAsync("button[type=\"submit\"]");await Page.WaitForURLAsync($"{BaseUrl}/`);
}

结合配置文件(appsettings.Test.json)控制不同框架的路由前缀,实现一套脚本多端复用。


http://www.xdnf.cn/news/1158409.html

相关文章:

  • 苍穹外卖|项目日记(完工总结)
  • 基于Transformer的智能对话系统:FastAPI后端与Streamlit前端实现
  • 【RK3576】【Android14】ADB工具说明与使用
  • 企业级安全威胁检测与响应(EDR/XDR)架构设计
  • xavier nx上编译fast-livo过程中出现的问题记录
  • C++现代编程之旅:从基础语法到高性能应用开发
  • 【GameMaker】GML v3 的现行提案
  • Numpy库,矩阵形状与维度操作
  • (5)从零开发 Chrome 插件:Vue3 Chrome 插件待办事项应用
  • Vue3.6 无虚拟DOM模式
  • An End-to-End Attention-Based Approach for Learning on Graphs NC 2025
  • 线程(一):基本概念
  • 让黑窗口变彩色:C++控制台颜色修改指南
  • week4
  • 内网后渗透攻击过程(实验环境)--3、横向攻击
  • MES系列 - MES是提升制造执行效率与透明度的关键系统
  • 【自动驾驶黑科技】基于Frenet坐标系的车道变换轨迹规划系统实现(附完整代码)
  • 多目标轨迹优化车道变换规划:自动驾驶轨迹规划新范式:基于Frenet坐标系的车道变换算法全解析
  • 枪战验证系统:通过战斗证明你是人类
  • 单片机启动流程和启动文件详解
  • [Linux]进程 / PID
  • [硬件电路-57]:根据电子元器件的受控程度,可以把电子元器件分为:不受控、半受控、完全受控三种大类
  • 非线性优化框架CasADi工具箱求解最优控制问题OCP
  • 什么是卡贴???
  • 零基础学习性能测试第一章:核心性能指标-并发量
  • 简洁高效的C++终端日志工具类
  • 2.组合式API知识点(1)
  • Dev-C++——winAPI贪吃蛇小游戏
  • Softhub软件下载站实战开发(十九):软件信息展示
  • 让不符合要求的任何电脑升级Windows11