5月30日 22:48
How does whistle support automated testing and what are testing framework integration solutions?
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