答案
Whistle 支持自动化测试,可以与各种测试框架集成,提高测试效率和质量。
自动化测试基础
1. 测试环境配置
安装测试依赖:
bashnpm install --save-dev whistle puppeteer jest
配置测试环境:
javascript// setup-whistle.js const { spawn } = require('child_process'); let whistleProcess; beforeAll(async () => { // 启动 whistle whistleProcess = spawn('w2', ['start', '-p', '8899']); // 等待 whistle 启动 await new Promise(resolve => setTimeout(resolve, 3000)); }); afterAll(async () => { // 停止 whistle spawn('w2', ['stop']); // 等待 whistle 停止 await new Promise(resolve => setTimeout(resolve, 1000)); });
Jest 集成
1. 基本测试用例
创建测试文件:whistle.test.js
javascriptconst puppeteer = require('puppeteer'); const fs = require('fs'); const path = require('path'); describe('Whistle Tests', () => { let browser; let page; beforeAll(async () => { browser = await puppeteer.launch({ args: ['--proxy-server=127.0.0.1:8899'] }); page = await browser.newPage(); }); afterAll(async () => { await browser.close(); }); test('should proxy requests correctly', async () => { // 配置 whistle 规则 const rules = 'www.example.com host 127.0.0.1:3000'; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // 访问测试页面 await page.goto('http://www.example.com'); // 验证请求被代理 const response = await page.goto('http://www.example.com'); expect(response.status()).toBe(200); }); test('should mock API responses', async () => { // 配置 mock 规则 const mockData = JSON.stringify({ code: 0, data: 'mock' }); const rules = `www.example.com/api/user resBody://${mockData}`; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // 访问 API const response = await page.goto('http://www.example.com/api/user'); const data = await response.json(); expect(data.code).toBe(0); expect(data.data).toBe('mock'); }); });
2. 高级测试用例
测试跨域处理:
javascripttest('should handle CORS correctly', async () => { // 配置 CORS 规则 const corsHeaders = JSON.stringify({ 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS' }); const rules = `www.example.com resHeaders://${corsHeaders}`; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // 测试跨域请求 const response = await page.evaluate(async () => { const res = await fetch('http://www.example.com/api/data'); return res.json(); }); expect(response).toBeDefined(); });
测试 HTTPS 拦截:
javascripttest('should intercept HTTPS requests', async () => { // 配置 HTTPS 规则 const rules = 'https://www.example.com host 127.0.0.1:3000'; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // 访问 HTTPS 页面 const response = await page.goto('https://www.example.com'); expect(response.status()).toBe(200); });
Cypress 集成
1. 配置 Cypress
创建配置文件:cypress.config.js
javascriptconst { defineConfig } = require('cypress'); module.exports = defineConfig({ e2e: { setupNodeEvents(on, config) { // 配置浏览器代理 on('before:browser:launch', (browser, launchOptions) => { launchOptions.args.push(`--proxy-server=http://127.0.0.1:8899`); return launchOptions; }); }, }, });
2. 创建测试用例
创建测试文件:cypress/e2e/whistle.cy.js
javascriptdescribe('Whistle E2E Tests', () => { beforeEach(() => { // 配置 whistle 规则 cy.task('setWhistleRules', 'www.example.com host 127.0.0.1:3000'); }); it('should proxy requests correctly', () => { cy.visit('http://www.example.com'); cy.contains('Example Domain').should('be.visible'); }); it('should mock API responses', () => { const mockData = { code: 0, data: 'mock' }; cy.task('setWhistleRules', `www.example.com/api/user resBody://${JSON.stringify(mockData)}`); cy.request('http://www.example.com/api/user').then((response) => { expect(response.body.code).to.equal(0); expect(response.body.data).to.equal('mock'); }); }); });
3. 配置 Cypress 任务
创建任务文件:cypress/plugins/index.js
javascriptconst fs = require('fs'); const path = require('path'); module.exports = (on, config) => { on('task', { setWhistleRules(rules) { const rulesPath = path.join(__dirname, '../../test.rules'); fs.writeFileSync(rulesPath, rules); return null; }, }); };
Playwright 集成
1. 配置 Playwright
创建配置文件:playwright.config.js
javascriptconst { defineConfig, devices } = require('@playwright/test'); module.exports = defineConfig({ use: { proxy: { server: 'http://127.0.0.1:8899', }, }, });
2. 创建测试用例
创建测试文件:whistle.spec.js
javascriptconst { test, expect } = require('@playwright/test'); const fs = require('fs'); const path = require('path'); test.describe('Whistle Playwright Tests', () => { test.beforeEach(async () => { // 配置 whistle 规则 const rules = 'www.example.com host 127.0.0.1:3000'; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); }); test('should proxy requests correctly', async ({ page }) => { await page.goto('http://www.example.com'); const title = await page.title(); expect(title).toContain('Example Domain'); }); test('should mock API responses', async ({ page, request }) => { const mockData = { code: 0, data: 'mock' }; const rules = `www.example.com/api/user resBody://${JSON.stringify(mockData)}`; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); const response = await request.get('http://www.example.com/api/user'); const data = await response.json(); expect(data.code).toBe(0); expect(data.data).toBe('mock'); }); });
性能测试
1. 使用 Lighthouse
创建性能测试:
javascriptconst lighthouse = require('lighthouse'); const chromeLauncher = require('chrome-launcher'); test('should meet performance standards', async () => { const chrome = await chromeLauncher.launch({ chromeFlags: ['--proxy-server=127.0.0.1:8899'] }); const options = { logLevel: 'info', output: 'json', port: chrome.port }; const runnerResult = await lighthouse('http://www.example.com', options); const metrics = runnerResult.lhr.audits; expect(metrics['first-contentful-paint'].numericValue).toBeLessThan(2000); expect(metrics['interactive'].numericValue).toBeLessThan(5000); await chrome.kill(); });
2. 使用 WebPageTest
创建性能测试脚本:
javascriptconst WebPageTest = require('webpagetest'); test('should meet WebPageTest standards', async () => { const wpt = new WebPageTest('www.webpagetest.org', 'YOUR_API_KEY'); const result = await wpt.runTest('http://www.example.com', { location: 'Dulles:Chrome', firstViewOnly: true, proxy: '127.0.0.1:8899' }); const data = result.data; expect(data.average.firstView.TTFB).toBeLessThan(500); expect(data.average.firstView.loadTime).toBeLessThan(3000); });
API 测试
1. 使用 Supertest
创建 API 测试:
javascriptconst request = require('supertest'); const express = require('express'); const app = express(); app.get('/api/test', (req, res) => { res.json({ message: 'success' }); }); test('should proxy API requests correctly', async () => { // 配置 whistle 规则 const rules = 'api.example.com host 127.0.0.1:3000'; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // 测试 API 请求 const response = await request(app) .get('/api/test') .set('Host', 'api.example.com') .expect(200); expect(response.body.message).toBe('success'); });
2. 使用 Axios
创建 API 测试:
javascriptconst axios = require('axios'); test('should handle API responses correctly', async () => { // 配置 whistle 规则 const mockData = { code: 0, data: 'test' }; const rules = `api.example.com/api/test resBody://${JSON.stringify(mockData)}`; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // 测试 API 请求 const response = await axios.get('http://api.example.com/api/test'); expect(response.data.code).toBe(0); expect(response.data.data).toBe('test'); });
CI/CD 集成
1. GitHub Actions
创建工作流文件:.github/workflows/test.yml
yamlname: Test on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v2 with: node-version: '16' - name: Install dependencies run: npm install - name: Install whistle run: npm install -g whistle - name: Start whistle run: w2 start -p 8899 - name: Run tests run: npm test - name: Stop whistle run: w2 stop
2. Jenkins Pipeline
创建 Jenkinsfile:
groovypipeline { agent any stages { stage('Setup') { steps { sh 'npm install' sh 'npm install -g whistle' sh 'w2 start -p 8899' } } stage('Test') { steps { sh 'npm test' } } stage('Cleanup') { steps { sh 'w2 stop' } } } }
最佳实践
-
隔离测试环境
- 使用独立的测试端口
- 配置独立的规则文件
- 避免测试互相干扰
-
清理测试资源
- 测试后清理规则文件
- 停止 whistle 进程
- 清理临时文件
-
使用 Mock 数据
- 使用固定的 Mock 数据
- 避免依赖外部服务
- 提高测试稳定性
-
并行测试
- 使用不同的端口
- 配置独立的 whistle 实例
- 提高测试效率
-
监控测试结果
- 记录测试日志
- 分析失败原因
- 持续优化测试