Answer
Whistle supports automated testing and can integrate with various testing frameworks to improve testing efficiency and quality.
Automated Testing Basics
1. Test Environment Configuration
Install test dependencies:
bashnpm install --save-dev whistle puppeteer jest
Configure test environment:
javascript// setup-whistle.js const { spawn } = require('child_process'); let whistleProcess; beforeAll(async () => { // Start whistle whistleProcess = spawn('w2', ['start', '-p', '8899']); // Wait for whistle to start await new Promise(resolve => setTimeout(resolve, 3000)); }); afterAll(async () => { // Stop whistle spawn('w2', ['stop']); // Wait for whistle to stop await new Promise(resolve => setTimeout(resolve, 1000)); });
Jest Integration
1. Basic Test Cases
Create test file: 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 () => { // Configure whistle rules const rules = 'www.example.com host 127.0.0.1:3000'; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // Visit test page await page.goto('http://www.example.com'); // Verify request is proxied const response = await page.goto('http://www.example.com'); expect(response.status()).toBe(200); }); test('should mock API responses', async () => { // Configure mock rules 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); // Visit 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. Advanced Test Cases
Test CORS handling:
javascripttest('should handle CORS correctly', async () => { // Configure CORS rules 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); // Test cross-origin request const response = await page.evaluate(async () => { const res = await fetch('http://www.example.com/api/data'); return res.json(); }); expect(response).toBeDefined(); });
Test HTTPS interception:
javascripttest('should intercept HTTPS requests', async () => { // Configure HTTPS rules const rules = 'https://www.example.com host 127.0.0.1:3000'; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // Visit HTTPS page const response = await page.goto('https://www.example.com'); expect(response.status()).toBe(200); });
Cypress Integration
1. Configure Cypress
Create config file: cypress.config.js
javascriptconst { defineConfig } = require('cypress'); module.exports = defineConfig({ e2e: { setupNodeEvents(on, config) { // Configure browser proxy on('before:browser:launch', (browser, launchOptions) => { launchOptions.args.push(`--proxy-server=http://127.0.0.1:8899`); return launchOptions; }); }, }, });
2. Create Test Cases
Create test file: cypress/e2e/whistle.cy.js
javascriptdescribe('Whistle E2E Tests', () => { beforeEach(() => { // Configure whistle rules 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. Configure Cypress Tasks
Create task file: 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 Integration
1. Configure Playwright
Create config file: playwright.config.js
javascriptconst { defineConfig, devices } = require('@playwright/test'); module.exports = defineConfig({ use: { proxy: { server: 'http://127.0.0.1:8899', }, }, });
2. Create Test Cases
Create test file: 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 () => { // Configure whistle rules 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'); }); });
Performance Testing
1. Use Lighthouse
Create performance test:
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. Use WebPageTest
Create performance test script:
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 Testing
1. Use Supertest
Create API test:
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 () => { // Configure whistle rules const rules = 'api.example.com host 127.0.0.1:3000'; fs.writeFileSync(path.join(__dirname, 'test.rules'), rules); // Test API request const response = await request(app) .get('/api/test') .set('Host', 'api.example.com') .expect(200); expect(response.body.message).toBe('success'); });
2. Use Axios
Create API test:
javascriptconst axios = require('axios'); test('should handle API responses correctly', async () => { // Configure whistle rules 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); // Test API request 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 Integration
1. GitHub Actions
Create workflow file: .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
Create 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' } } } }
Best Practices
-
Isolate Test Environment
- Use independent test ports
- Configure independent rule files
- Avoid test interference
-
Clean Up Test Resources
- Clean up rule files after tests
- Stop whistle processes
- Clean up temporary files
-
Use Mock Data
- Use fixed mock data
- Avoid dependency on external services
- Improve test stability
-
Parallel Testing
- Use different ports
- Configure independent whistle instances
- Improve test efficiency
-
Monitor Test Results
- Record test logs
- Analyze failure reasons
- Continuously optimize tests