Files
telegram-management-system/marketing-agent/docs/TESTING.md
你的用户名 237c7802e5
Some checks failed
Deploy / deploy (push) Has been cancelled
Initial commit: Telegram Management System
Full-stack web application for Telegram management
- Frontend: Vue 3 + Vben Admin
- Backend: NestJS
- Features: User management, group broadcast, statistics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 15:37:50 +08:00

449 lines
9.8 KiB
Markdown

# Testing Documentation
Comprehensive testing guide for the Telegram Marketing Agent System.
## Table of Contents
- [Testing Strategy](#testing-strategy)
- [Test Types](#test-types)
- [Running Tests](#running-tests)
- [Writing Tests](#writing-tests)
- [CI/CD Integration](#cicd-integration)
- [Coverage Goals](#coverage-goals)
- [Best Practices](#best-practices)
## Testing Strategy
Our testing strategy follows the Testing Pyramid approach:
```
/\
/E2E\ (5-10%)
/------\
/Integration\ (20-30%)
/------------\
/ Unit Tests \ (60-70%)
/-----------------\
```
### Test Categories
1. **Unit Tests**: Test individual functions, methods, and components in isolation
2. **Integration Tests**: Test interactions between components and services
3. **End-to-End Tests**: Test complete user workflows and scenarios
## Test Types
### Unit Tests
Located in `tests/unit/`, these tests cover:
- Service methods
- Utility functions
- Middleware logic
- Model validations
- Helper functions
Example structure:
```
tests/unit/
├── services/
│ ├── api-gateway/
│ │ ├── middleware/
│ │ │ ├── auth.test.js
│ │ │ └── rateLimiter.test.js
│ │ └── utils/
│ └── orchestrator/
│ └── campaignService.test.js
└── utils/
```
### Integration Tests
Located in `tests/integration/`, these tests cover:
- API endpoint functionality
- Database operations
- Service interactions
- External API mocking
Example structure:
```
tests/integration/
├── api/
│ ├── auth.test.js
│ ├── campaigns.test.js
│ └── users.test.js
└── services/
```
### End-to-End Tests
Located in `tests/e2e/`, these tests cover:
- Complete user workflows
- Multi-service interactions
- Real-world scenarios
Example structure:
```
tests/e2e/
├── campaigns/
│ └── campaignWorkflow.test.js
└── users/
└── userOnboarding.test.js
```
## Running Tests
### Prerequisites
```bash
# Install dependencies
npm install
# For each service
cd services/<service-name>
npm install
```
### All Tests
```bash
npm test
```
### Unit Tests Only
```bash
npm run test:unit
```
### Integration Tests Only
```bash
npm run test:integration
```
### E2E Tests Only
```bash
npm run test:e2e
```
### Watch Mode (for development)
```bash
npm run test:watch
```
### Coverage Report
```bash
npm run test:coverage
```
### Specific Test File
```bash
npx jest tests/unit/services/orchestrator/campaignService.test.js
```
### Test Pattern
```bash
npx jest --testNamePattern="should create campaign"
```
## Writing Tests
### Unit Test Example
```javascript
import { jest } from '@jest/globals';
import CampaignService from '../../../../services/orchestrator/src/services/campaignService.js';
import { createCampaign } from '../../../helpers/factories.js';
describe('CampaignService', () => {
let campaignService;
let mockDependency;
beforeEach(() => {
// Setup mocks
mockDependency = {
method: jest.fn()
};
campaignService = new CampaignService(mockDependency);
jest.clearAllMocks();
});
describe('createCampaign', () => {
it('should create a new campaign', async () => {
// Arrange
const campaignData = createCampaign();
mockDependency.method.mockResolvedValue({ success: true });
// Act
const result = await campaignService.createCampaign(campaignData);
// Assert
expect(result).toHaveProperty('id');
expect(mockDependency.method).toHaveBeenCalledWith(expect.any(Object));
});
it('should handle errors gracefully', async () => {
// Arrange
mockDependency.method.mockRejectedValue(new Error('Database error'));
// Act & Assert
await expect(campaignService.createCampaign({}))
.rejects.toThrow('Database error');
});
});
});
```
### Integration Test Example
```javascript
import request from 'supertest';
import app from '../../../services/api-gateway/src/app.js';
import { connectDatabase, closeDatabase, clearDatabase } from '../../helpers/database.js';
describe('Campaigns API', () => {
let authToken;
beforeAll(async () => {
await connectDatabase();
authToken = await getAuthToken();
});
afterEach(async () => {
await clearDatabase();
});
afterAll(async () => {
await closeDatabase();
});
describe('POST /api/v1/campaigns', () => {
it('should create campaign', async () => {
const response = await request(app)
.post('/api/v1/campaigns')
.set('Authorization', `Bearer ${authToken}`)
.send({
name: 'Test Campaign',
type: 'message'
});
expect(response.status).toBe(201);
expect(response.body.success).toBe(true);
expect(response.body.data.campaign).toHaveProperty('id');
});
});
});
```
### E2E Test Example
```javascript
describe('Campaign Workflow', () => {
it('should complete full campaign lifecycle', async () => {
// 1. Create template
const template = await createTemplate();
// 2. Import users
const users = await importUsers();
// 3. Create segment
const segment = await createSegment();
// 4. Create campaign
const campaign = await createCampaign({
templateId: template.id,
segmentId: segment.id
});
// 5. Execute campaign
const execution = await executeCampaign(campaign.id);
// 6. Verify results
expect(execution.status).toBe('completed');
expect(execution.messagesSent).toBe(users.length);
});
});
```
## Test Helpers and Utilities
### Database Helpers
```javascript
import { connectDatabase, closeDatabase, clearDatabase } from './helpers/database.js';
```
### Factory Functions
```javascript
import {
createUser,
createCampaign,
createTemplate
} from './helpers/factories.js';
```
### Authentication Helpers
```javascript
import { generateAuthToken, createAuthenticatedRequest } from './helpers/auth.js';
```
## CI/CD Integration
Tests run automatically on:
- Pull requests
- Commits to main/develop branches
- Before deployments
### GitHub Actions Workflow
See `.github/workflows/test.yml` for the complete CI configuration.
Key features:
- Matrix testing (Node.js 18.x, 20.x)
- Multiple database versions
- Parallel test execution
- Coverage reporting
- Test result artifacts
### Pre-commit Hooks
```bash
# Install husky
npm prepare
# Pre-commit hook runs:
- Linting
- Unit tests for changed files
- Commit message validation
```
## Coverage Goals
### Overall Coverage Targets
- **Statements**: 80%
- **Branches**: 70%
- **Functions**: 70%
- **Lines**: 80%
### Service-Specific Targets
- **API Gateway**: 85% (critical path)
- **Orchestrator**: 80%
- **Analytics**: 75%
- **User Management**: 80%
- **Scheduler**: 75%
### Viewing Coverage
```bash
# Generate HTML coverage report
npm run test:coverage
# Open in browser
open coverage/lcov-report/index.html
```
## Best Practices
### General Guidelines
1. **Test Naming**: Use descriptive test names that explain what is being tested
```javascript
// Good
it('should return 404 when campaign does not exist')
// Bad
it('test campaign')
```
2. **Arrange-Act-Assert**: Structure tests clearly
```javascript
it('should calculate discount correctly', () => {
// Arrange
const price = 100;
const discountRate = 0.2;
// Act
const result = calculateDiscount(price, discountRate);
// Assert
expect(result).toBe(80);
});
```
3. **Isolation**: Each test should be independent
- Use `beforeEach` and `afterEach` for setup/cleanup
- Don't rely on test execution order
- Clear mocks between tests
4. **Mocking**: Mock external dependencies
```javascript
jest.mock('axios');
axios.get.mockResolvedValue({ data: mockData });
```
5. **Async Testing**: Handle promises properly
```javascript
// Good
it('should handle async operation', async () => {
await expect(asyncFunction()).resolves.toBe(expected);
});
// Also good
it('should handle async operation', () => {
return expect(asyncFunction()).resolves.toBe(expected);
});
```
6. **Error Testing**: Test error cases thoroughly
```javascript
it('should throw error for invalid input', async () => {
await expect(functionUnderTest(null))
.rejects.toThrow('Input cannot be null');
});
```
### Performance Considerations
1. **Use Test Databases**: MongoDB Memory Server for unit tests
2. **Parallel Execution**: Run independent tests in parallel
3. **Selective Testing**: Use `--watch` mode during development
4. **Mock Heavy Operations**: Mock file I/O, network calls
### Security Testing
1. **Authentication**: Test all auth scenarios
2. **Authorization**: Verify role-based access
3. **Input Validation**: Test with malicious inputs
4. **Rate Limiting**: Verify limits are enforced
## Troubleshooting
### Common Issues
1. **Timeout Errors**
```javascript
// Increase timeout for specific test
it('should handle long operation', async () => {
// test code
}, 10000); // 10 second timeout
```
2. **Database Connection Issues**
- Ensure MongoDB/Redis are running
- Check connection strings in test environment
- Clear test database between runs
3. **Flaky Tests**
- Add proper waits for async operations
- Mock time-dependent functions
- Use stable test data
4. **Memory Leaks**
- Close all connections in `afterAll`
- Clear large data structures
- Use `--detectLeaks` flag
## Additional Resources
- [Jest Documentation](https://jestjs.io/docs/getting-started)
- [Supertest Documentation](https://github.com/visionmedia/supertest)
- [MongoDB Memory Server](https://github.com/nodkz/mongodb-memory-server)
- [Testing Best Practices](https://github.com/goldbergyoni/javascript-testing-best-practices)