自动化测试实践指南
简介
自动化测试是现代软件开发中保证代码质量的重要手段。本文将介绍单元测试、集成测试和端到端测试的实践方法。
单元测试
1. Jest 配置
javascript
// jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
collectCoverageFrom: [
'src/**/*.{js,jsx,ts,tsx}',
'!src/**/*.d.ts'
]
};2. 测试用例
javascript
// math.test.js
import { add, subtract } from './math';
describe('Math functions', () => {
test('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
test('subtracts 5 - 3 to equal 2', () => {
expect(subtract(5, 3)).toBe(2);
});
});
// component.test.js
import { mount } from '@vue/test-utils';
import Counter from './Counter.vue';
describe('Counter.vue', () => {
test('increments count when button is clicked', async () => {
const wrapper = mount(Counter);
await wrapper.find('button').trigger('click');
expect(wrapper.find('.count').text()).toBe('1');
});
});集成测试
1. API 测试
javascript
// api.test.js
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
describe('API Integration', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
test('fetches user data successfully', async () => {
const userData = { id: 1, name: 'John' };
mock.onGet('/api/user/1').reply(200, userData);
const response = await axios.get('/api/user/1');
expect(response.data).toEqual(userData);
});
});2. 组件集成测试
javascript
// integration.test.js
import { mount } from '@vue/test-utils';
import { createStore } from 'vuex';
import App from './App.vue';
describe('App Integration', () => {
let store;
let wrapper;
beforeEach(() => {
store = createStore({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
}
});
wrapper = mount(App, {
global: {
plugins: [store]
}
});
});
test('updates store when incrementing', async () => {
await wrapper.find('button').trigger('click');
expect(store.state.count).toBe(1);
});
});端到端测试
1. Cypress 配置
javascript
// cypress.config.js
const { defineConfig } = require('cypress');
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:3000',
viewportWidth: 1280,
viewportHeight: 720,
video: false,
screenshotOnRunFailure: true
}
});2. E2E 测试用例
javascript
// cypress/e2e/login.cy.js
describe('Login Page', () => {
beforeEach(() => {
cy.visit('/login');
});
it('should login successfully with valid credentials', () => {
cy.get('[data-test="username"]').type('testuser');
cy.get('[data-test="password"]').type('password123');
cy.get('[data-test="submit"]').click();
cy.url().should('include', '/dashboard');
});
it('should show error with invalid credentials', () => {
cy.get('[data-test="username"]').type('wronguser');
cy.get('[data-test="password"]').type('wrongpass');
cy.get('[data-test="submit"]').click();
cy.get('[data-test="error"]').should('be.visible');
});
});测试覆盖率
1. 覆盖率配置
javascript
// jest.config.js
module.exports = {
collectCoverage: true,
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80
}
},
coverageReporters: ['text', 'lcov', 'html']
};2. 覆盖率报告
bash
# 运行测试并生成覆盖率报告
npm test -- --coverage
# 查看 HTML 报告
open coverage/lcov-report/index.html测试最佳实践
1. 测试组织
javascript
// 测试文件结构
src/
components/
Button/
Button.vue
Button.test.js
utils/
math.js
math.test.js
__tests__/
integration/
api.test.js
e2e/
login.test.js2. 测试数据
javascript
// test/fixtures/users.js
export const mockUsers = [
{ id: 1, name: 'John', email: 'john@example.com' },
{ id: 2, name: 'Jane', email: 'jane@example.com' }
];
// test/factories/user.js
export const createUser = (overrides = {}) => ({
id: 1,
name: 'Test User',
email: 'test@example.com',
...overrides
});持续集成
1. GitHub Actions
yaml
# .github/workflows/test.yml
name: 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: pnpm install
- name: Run tests
run: pnpm test
- name: Upload coverage
uses: codecov/codecov-action@v22. 测试报告
yaml
# .github/workflows/test-report.yml
name: Test Report
on:
workflow_run:
workflows: ["Test"]
types:
- completed
jobs:
report:
runs-on: ubuntu-latest
steps:
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ github.event.workflow_run.conclusion }}
fields: repo,message,commit,author,action,eventName,ref,workflow
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}最佳实践
测试策略
- 遵循测试金字塔
- 保持测试独立性
- 使用适当的测试工具
- 定期维护测试用例
代码质量
- 编写可测试的代码
- 使用测试驱动开发
- 保持测试代码整洁
- 及时更新测试用例
持续改进
- 监控测试覆盖率
- 分析测试失败原因
- 优化测试执行时间
- 定期审查测试策略
工具链
1. 测试工具
json
{
"devDependencies": {
"jest": "^27.0.0",
"cypress": "^10.0.0",
"@testing-library/vue": "^7.0.0",
"@vue/test-utils": "^2.0.0",
"axios-mock-adapter": "^1.20.0"
}
}2. 测试辅助工具
json
{
"devDependencies": {
"faker": "^5.5.0",
"msw": "^0.40.0",
"sinon": "^12.0.0",
"testdouble": "^3.16.0"
}
}总结
自动化测试是保证软件质量的重要手段,通过合理使用测试工具和遵循最佳实践,可以构建出可靠、可维护的测试体系。