Files
你的用户名 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

9.8 KiB

Testing Documentation

Comprehensive testing guide for the Telegram Marketing Agent System.

Table of Contents

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

# Install dependencies
npm install

# For each service
cd services/<service-name>
npm install

All Tests

npm test

Unit Tests Only

npm run test:unit

Integration Tests Only

npm run test:integration

E2E Tests Only

npm run test:e2e

Watch Mode (for development)

npm run test:watch

Coverage Report

npm run test:coverage

Specific Test File

npx jest tests/unit/services/orchestrator/campaignService.test.js

Test Pattern

npx jest --testNamePattern="should create campaign"

Writing Tests

Unit Test Example

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

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

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

import { connectDatabase, closeDatabase, clearDatabase } from './helpers/database.js';

Factory Functions

import { 
  createUser, 
  createCampaign, 
  createTemplate 
} from './helpers/factories.js';

Authentication Helpers

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

# 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

# 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

    // Good
    it('should return 404 when campaign does not exist')
    
    // Bad
    it('test campaign')
    
  2. Arrange-Act-Assert: Structure tests clearly

    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

    jest.mock('axios');
    axios.get.mockResolvedValue({ data: mockData });
    
  5. Async Testing: Handle promises properly

    // 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

    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

    // 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