开封市网站建设_网站建设公司_腾讯云_seo优化
2026/1/16 17:01:50 网站建设 项目流程

当你的E2E测试套件执行时间从几分钟膨胀到半小时,每天能完整运行的次数屈指可数时,优化就不再是可选项,而是必需品。我们团队曾面对一个45分钟的测试套件,通过系统优化最终将其缩减到8分钟。以下是经过实战验证的10个技巧。

1. 并行化:性价比最高的优化

这是最能立竿见影的手段。Playwright原生支持并行执行,你只需要调整配置:

// playwright.config.ts export default { workers: process.env.CI ? 4 : 2, // CI环境用4个worker,本地用2个 fullyParallel: true, // 所有测试文件并行执行 // 如果你的测试有状态依赖,可以改为: // fullyParallel: false, // 但依然可以保持worker数量 };

关键在于测试文件的独立性。如果有全局状态(如共享数据库),你需要通过beforeAllafterAll来管理测试隔离。在我们的实践中,仅开启并行化就将执行时间减少了65%。

2. 浏览器复用:减少启动开销

每次测试都启动新浏览器会浪费大量时间。改为复用浏览器实例:

// 在配置中开启 exportdefault { use: { headless: true, // 复用浏览器上下文而非每次都创建新的 launchOptions: { args: ['--no-sandbox'] } }, }; // 测试文件中 test.describe.configure({ mode: 'parallel' }); // 让describe内测试也并行 // 或者手动管理浏览器实例 let browser: Browser; test.beforeAll(async () => { browser = await chromium.launch(); }); test.beforeEach(async ({ page }) => { // 从已有浏览器创建上下文 const context = await browser.newContext(); page = await context.newPage(); });

注意:浏览器复用可能导致测试间状态污染,确保每个测试有独立的browserContext

3. 选择性执行:只跑必要的测试

不是每次提交都需要跑全部测试。建立分层策略:

{ "scripts": { "test:smoke": "playwright test --grep '@smoke'", "test:regression": "playwright test --grep '@regression'", "test:changed": "playwright test $(git diff --name-only HEAD~1 | grep -E '\\.spec\\.ts$')" } }

在测试文件中使用标签:

test('关键登录流程 @smoke', async ({ page }) => { // 冒烟测试,每次CI都执行 }); test('边界条件测试 @regression', async ({ page }) => { // 回归测试,每日执行 });

我们团队设置了预提交钩子只跑@smoke测试,夜间CI跑完整套件,平衡了速度和覆盖率。

4. 智能等待:告别硬编码sleep

硬编码的sleep是性能杀手,也是脆弱的根源:

// ❌ 糟糕的做法 await page.waitForTimeout(5000); // 无论实际需要多久都等5秒 // ✅ 正确的做法 // 等待页面加载完成 await page.waitForLoadState('networkidle'); // 等待特定元素出现 await page.locator('.data-loaded').waitFor({ state: 'visible' }); // 等待API请求完成 const responsePromise = page.waitForResponse('/api/data'); await page.click('#load-data'); const response = await responsePromise; // 自定义等待条件 await page.waitForFunction( () =>document.querySelectorAll('.item').length >= 10 );

优化后,我们的测试平均等待时间从固定的5秒降到了0.5-2秒,具体取决于网络和业务逻辑。

5. 数据准备:预置而非动态生成

避免在测试中执行耗时操作:

// ❌ 每个测试都创建用户 test('用户操作', async () => { const user = await createUserViaAPI(); // 每次调用都走完整流程 // 测试逻辑... }); // ✅ 预置测试数据 // 在全局setup中 import { seedDatabase } from'./test-data'; asyncfunction globalSetup() { await seedDatabase({ standardUsers: 5, adminUsers: 1, products: 50 }); } // 测试中直接使用 test('用户操作', async ({ page }) => { await page.goto(`/user/${process.env.TEST_USER_ID}`); // 使用预置用户 // 测试逻辑... });

我们为测试环境准备了快照数据库,每个测试套件开始时恢复快照,这比每个测试都清理数据快得多。

6. 资源拦截:阻止不必要的加载

页面加载的图片、字体、分析脚本对测试毫无价值:

// 在配置中或beforeEach中 await page.route('**/*.{png,jpg,jpeg,gif,svg}', route => route.abort()); await page.route('**/analytics.js', route => route.abort()); await page.route('**/ads/*', route => route.abort()); // 或者更精细的控制 await page.route('**/*', route => { const resourceType = route.request().resourceType(); // 只允许必要的资源类型 const blockedTypes = ['image', 'media', 'font']; if (blockedTypes.includes(resourceType)) { return route.abort(); } return route.continue(); });

这个简单的拦截策略让我们的页面加载时间平均减少了40%。

7. 测试分割:平衡并行和串行

不是所有测试都能完美并行。混合策略效果更好:

// 配置文件 exportdefault { // 为串行测试创建单独的项目 projects: [ { name: '串行-关键路径', testMatch: '**/*.critical.spec.ts', fullyParallel: false, workers: 1 }, { name: '并行-功能测试', testMatch: '**/*.spec.ts', testIgnore: '**/*.critical.spec.ts', fullyParallel: true, workers: 4 } ] }; // 或者在同一文件中混合 test.describe.serial('用户注册流程', () => { // 这些测试有严格顺序依赖 test('步骤1: 填写信息', () => {}); test('步骤2: 验证邮箱', () => {}); test('步骤3: 完善资料', () => {}); }); test.describe('商品浏览功能', () => { // 这些测试可并行 test('搜索商品', () => {}); test('筛选结果', () => {}); test('排序商品', () => {}); });

8. 缓存利用:复用登录状态

登录通常是测试中最耗时的部分:

// storageState.ts - 创建可复用的认证状态 import { test as setup } from'@playwright/test'; setup('准备登录状态', async ({ page }) => { await page.goto('/login'); await page.fill('#username', 'testuser'); await page.fill('#password', 'password123'); await page.click('#submit'); await page.waitForURL('/dashboard'); // 保存状态 await page.context().storageState({ path: 'playwright/.auth/user.json' }); }); // playwright.config.ts exportdefault { use: { // 所有测试复用该状态 storageState: 'playwright/.auth/user.json' }, globalSetup: require.resolve('./storageState.ts') }; // 测试文件中直接访问已登录页面 test('访问仪表盘', async ({ page }) => { await page.goto('/dashboard'); // 已经是登录状态 // 无需再次登录 });

注意:定期更新缓存状态,避免会话过期。

9. 基础设施优化:硬件和环境

软件优化到极限后,看看硬件:

# GitHub Actions示例 jobs: test: runs-on:ubuntu-latest strategy: matrix: shard:[1,2,3,4]# 分片执行 steps: -uses:actions/setup-node@v3 with: node-version:'18' -run:| # 只安装必要依赖 npm ci --omit=dev --ignore-scripts # 单独安装测试相关依赖 npm install @playwright/test playwright -run:| # 分片执行 npx playwright test --shard=${{ matrix.shard }}/${{ strategy.job-total }} -uses:actions/upload-artifact@v3 if:always() with: name:playwright-report-${{matrix.shard}} path:playwright-report/

本地开发时,确保Node.js是最新LTS版本(V8引擎的持续优化能提升执行速度),考虑使用SSD而非HDD。

10. 持续监控:建立性能基线

优化不是一劳永逸的。建立监控机制:

// 收集性能指标 test('性能回归检查', async ({ page }) => { const startTime = Date.now(); // 执行关键操作 await page.goto('/dashboard'); await page.click('#load-report'); await page.waitForSelector('.report-loaded'); const duration = Date.now() - startTime; // 记录到文件或外部系统 console.log(`执行时间: ${duration}ms`); // 断言性能要求 expect(duration).toBeLessThan(3000); // 必须小于3秒 }); // 使用Playwright的trace功能分析慢测试 exportdefault { use: { trace: process.env.CI ? 'on-first-retry' : 'retain-on-failure', // 或者只为慢测试记录trace trace: { mode: 'on', snapshots: true, screenshots: true } } };

我们团队设置了一个仪表板,跟踪每次提交的测试执行时间,当某个测试突然变慢时立即告警。

实战组合拳

没有单一银弹,真正有效的是组合策略。我们的优化路径是:先上并行化(见效最快),然后优化等待逻辑和数据准备,接着实现分层测试和资源拦截,最后通过基础设施和监控巩固成果。

记住:优化应该基于数据。使用--reporter=line查看每个测试的时间,优先优化最耗时的10%的测试。有些测试可能本身就应该是慢的(如完整业务流程),不要过度优化。

现在,你们的测试套件还在苦苦挣扎吗?从第一点开始,今天就能看到效果。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询