Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

Test Automation - automatyczne kontrole jakości

Witaj, mistrzu automatyki! Konsul Caesar.js odkrył, że najlepsze forty to te, które mają automatyczne systemy kontrolujące każdy aspekt kampanii. Test Automation to magiczna maszyna, która pilnuje jakości kodu 24/7, nawet gdy śpisz!

Czym jest Test Automation?

Test Automation to jak zautomatyzowane systemy fortu:

  • Automatyczne alarmy - CI/CD pipelines
  • Samokontrola systemów - automated test suites
  • Regularne inspekcje - scheduled test runs
  • Natychmiastowe powiadomienia - instant feedback
  • Zapobieganie katastrofom - preventing bad code from deploying
1# Przykład - automatyczny pipeline kontroli jakości
2name: Legionary Legion Quality Control
3
4on:
5 push:
6 branches: [main, develop]
7 pull_request:
8 branches: [main]
9
10jobs:
11 quality-control:
12 runs-on: ubuntu-latest
13 steps:
14 - name: Check out the cohort
15 uses: actions/checkout@v3
16 
17 - name: 🦅 Setup Node.js
18 uses: actions/setup-node@v3
19 with:
20 node-version: '18'
21 
22 - name: Load cargo (dependencies)
23 run: npm ci
24 
25 - name: Lint check (inspect the cohort)
26 run: npm run lint
27 
28 - name: 🧪 Run all tests
29 run: npm run test:cov
30 
31 - name: Build the cohort
32 run: npm run build

CI/CD Pipeline Setup dla NestJS

GitHub Actions Configuration

1# .github/workflows/ci.yml
2name: Continuous Integration
3
4on:
5 push:
6 branches: [main, develop, 'feature/*']
7 pull_request:
8 branches: [main, develop]
9
10env:
11 NODE_VERSION: '18'
12 POSTGRES_DB: legionariusze_test_db
13 POSTGRES_USER: test_user
14 POSTGRES_PASSWORD: test_password
15
16jobs:
17 # Job 1: Code Quality Checks
18 code-quality:
19 name: Code Quality
20 runs-on: ubuntu-latest
21 
22 steps:
23 - name: Checkout repository
24 uses: actions/checkout@v3
25 
26 - name: Setup Node.js
27 uses: actions/setup-node@v3
28 with:
29 node-version: ${{ env.NODE_VERSION }}
30 cache: 'npm'
31 
32 - name: Install dependencies
33 run: npm ci
34 
35 - name: Run ESLint
36 run: npm run lint
37 
38 - name: Run Prettier check
39 run: npm run format:check
40 
41 - name: TypeScript type check
42 run: npm run type-check
43 
44 - name: Check for security vulnerabilities
45 run: npm audit --audit-level high
46 
47 # Job 2: Unit Tests
48 unit-tests:
49 name: 🧪 Unit Tests
50 runs-on: ubuntu-latest
51 needs: code-quality
52 
53 steps:
54 - name: Checkout repository
55 uses: actions/checkout@v3
56 
57 - name: Setup Node.js
58 uses: actions/setup-node@v3
59 with:
60 node-version: ${{ env.NODE_VERSION }}
61 cache: 'npm'
62 
63 - name: Install dependencies
64 run: npm ci
65 
66 - name: Run unit tests with coverage
67 run: npm run test:cov
68 
69 - name: Upload coverage to Codecov
70 uses: codecov/codecov-action@v3
71 with:
72 file: ./coverage/lcov.info
73 flags: unittests
74 name: codecov-umbrella
75 
76 - name: Coverage Comment
77 uses: romeovs/lcov-reporter-action@v0.3.1
78 with:
79 github-token: ${{ secrets.GITHUB_TOKEN }}
80 lcov-file: ./coverage/lcov.info
81 delete-old-comments: true
82 
83 # Job 3: Integration Tests
84 integration-tests:
85 name: Integration Tests
86 runs-on: ubuntu-latest
87 needs: unit-tests
88 
89 services:
90 postgres:
91 image: postgres:13
92 env:
93 POSTGRES_DB: ${{ env.POSTGRES_DB }}
94 POSTGRES_USER: ${{ env.POSTGRES_USER }}
95 POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
96 options: >-
97 --health-cmd pg_isready
98 --health-interval 10s
99 --health-timeout 5s
100 --health-retries 5
101 ports:
102 - 5432:5432
103 
104 redis:
105 image: redis:6
106 options: >-
107 --health-cmd "redis-cli ping"
108 --health-interval 10s
109 --health-timeout 5s
110 --health-retries 5
111 ports:
112 - 6379:6379
113 
114 steps:
115 - name: Checkout repository
116 uses: actions/checkout@v3
117 
118 - name: Setup Node.js
119 uses: actions/setup-node@v3
120 with:
121 node-version: ${{ env.NODE_VERSION }}
122 cache: 'npm'
123 
124 - name: Install dependencies
125 run: npm ci
126 
127 - name: Run database migrations
128 run: npm run migration:run
129 env:
130 DATABASE_URL: postgres://test_user:test_password@localhost:5432/legionariusze_test_db
131 
132 - name: Run integration tests
133 run: npm run test:integration
134 env:
135 DATABASE_URL: postgres://test_user:test_password@localhost:5432/legionariusze_test_db
136 REDIS_URL: redis://localhost:6379
137 
138 # Job 4: E2E Tests
139 e2e-tests:
140 name: E2E Tests
141 runs-on: ubuntu-latest
142 needs: integration-tests
143 
144 services:
145 postgres:
146 image: postgres:13
147 env:
148 POSTGRES_DB: ${{ env.POSTGRES_DB }}
149 POSTGRES_USER: ${{ env.POSTGRES_USER }}
150 POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
151 options: >-
152 --health-cmd pg_isready
153 --health-interval 10s
154 --health-timeout 5s
155 --health-retries 5
156 ports:
157 - 5432:5432
158 
159 steps:
160 - name: Checkout repository
161 uses: actions/checkout@v3
162 
163 - name: Setup Node.js
164 uses: actions/setup-node@v3
165 with:
166 node-version: ${{ env.NODE_VERSION }}
167 cache: 'npm'
168 
169 - name: Install dependencies
170 run: npm ci
171 
172 - name: Build application
173 run: npm run build
174 
175 - name: Start application
176 run: |
177 npm run start:prod &
178 sleep 10
179 env:
180 DATABASE_URL: postgres://test_user:test_password@localhost:5432/legionariusze_test_db
181 
182 - name: Run E2E tests
183 run: npm run test:e2e
184 
185 - name: Upload E2E test artifacts
186 if: failure()
187 uses: actions/upload-artifact@v3
188 with:
189 name: e2e-test-results
190 path: |
191 test-results/
192 screenshots/
193 
194 # Job 5: Security Scan
195 security-scan:
196 name: Security Scan
197 runs-on: ubuntu-latest
198 needs: code-quality
199 
200 steps:
201 - name: Checkout repository
202 uses: actions/checkout@v3
203 
204 - name: Run Snyk to check for vulnerabilities
205 uses: snyk/actions/node@master
206 env:
207 SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
208 with:
209 args: --severity-threshold=high
210 
211 - name: Upload Snyk results to GitHub Code Scanning
212 uses: github/codeql-action/upload-sarif@v2
213 if: always()
214 with:
215 sarif_file: snyk.sarif
216 
217 # Job 6: Performance Tests
218 performance-tests:
219 name: Performance Tests
220 runs-on: ubuntu-latest
221 needs: integration-tests
222 if: github.event_name == 'push' && github.ref == 'refs/heads/main'
223 
224 steps:
225 - name: Checkout repository
226 uses: actions/checkout@v3
227 
228 - name: Setup Node.js
229 uses: actions/setup-node@v3
230 with:
231 node-version: ${{ env.NODE_VERSION }}
232 cache: 'npm'
233 
234 - name: Install dependencies
235 run: npm ci
236 
237 - name: Run performance tests
238 run: npm run test:performance
239 
240 - name: Upload performance results
241 uses: actions/upload-artifact@v3
242 with:
243 name: performance-results
244 path: performance-results.json

Pre-commit Hooks - kontrola przed załadunkiem

Husky + lint-staged Setup

1// package.json
2{
3 "scripts": {
4 "prepare": "husky install",
5 "lint": "eslint "{src,apps,libs,test}/**/*.ts" --fix",
6 "format": "prettier --write "src/**/*.ts" "test/**/*.ts"",
7 "format:check": "prettier --check "src/**/*.ts" "test/**/*.ts"",
8 "type-check": "tsc --noEmit"
9 },
10 "lint-staged": {
11 "*.{ts,js}": [
12 "eslint --fix",
13 "prettier --write",
14 "git add"
15 ],
16 "*.ts": [
17 "npm run type-check"
18 ]
19 },
20 "husky": {
21 "hooks": {
22 "pre-commit": "lint-staged",
23 "pre-push": "npm run test:unit",
24 "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
25 }
26 }
27}

Custom pre-commit script

1#!/bin/sh
2# .husky/pre-commit
3
4echo " Running pre-commit checks..."
5
6# Run lint-staged
7echo " Checking code style..."
8npx lint-staged
9
10# Run affected tests only
11echo "🧪 Running tests for changed files..."
12npm run test:changed
13
14# Check if there are any TODO/FIXME comments in staged files
15echo " Checking for TODO/FIXME comments..."
16TODOS=$(git diff --cached --name-only | xargs grep -l "TODO|FIXME" || true)
17if [ ! -z "$TODOS" ]; then
18 echo " Found TODO/FIXME comments in staged files:"
19 echo "$TODOS"
20 echo "Please resolve them before committing."
21 exit 1
22fi
23
24# Check for debugging statements
25echo "Checking for debugging statements..."
26DEBUG_STATEMENTS=$(git diff --cached --name-only | xargs grep -l "console.log|debugger" || true)
27if [ ! -z "$DEBUG_STATEMENTS" ]; then
28 echo " Found debugging statements in staged files:"
29 echo "$DEBUG_STATEMENTS"
30 echo "Please remove them before committing."
31 exit 1
32fi
33
34echo "✅ All pre-commit checks passed! Ready to march!"

Branch Protection Rules

GitHub Branch Protection

1# .github/branch-protection.yml
2branch_protection_rules:
3 main:
4 required_status_checks:
5 strict: true
6 contexts:
7 - "Code Quality"
8 - "Unit Tests"
9 - "Integration Tests"
10 - "E2E Tests"
11 - "Security Scan"
12 enforce_admins: true
13 required_pull_request_reviews:
14 required_approving_review_count: 2
15 dismiss_stale_reviews: true
16 require_code_owner_reviews: true
17 restrictions:
18 users: []
19 teams: ["senior-legionariuszes"]

Automated Testing Strategies

Test Organization

1// test/automation/test-suites.ts
2export class AutomatedTestSuites {
3 static getCriticalTests(): TestSuite[] {
4 return [
5 {
6 name: 'Authentication Flow',
7 tests: [
8 'user-login.e2e.spec.ts',
9 'user-registration.e2e.spec.ts',
10 'password-reset.e2e.spec.ts'
11 ],
12 timeout: 30000,
13 retries: 2
14 },
15 {
16 name: 'Core Business Logic',
17 tests: [
18 'tribute-management.spec.ts',
19 'expedition-planning.spec.ts',
20 'legion-assignment.spec.ts'
21 ],
22 timeout: 10000,
23 retries: 1
24 },
25 {
26 name: 'Data Integrity',
27 tests: [
28 'database-transactions.spec.ts',
29 'data-validation.spec.ts',
30 'backup-restore.spec.ts'
31 ],
32 timeout: 60000,
33 retries: 0
34 }
35 ];
36 }
37 
38 static getPerformanceTests(): TestSuite[] {
39 return [
40 {
41 name: 'Load Testing',
42 tests: ['load-test.spec.ts'],
43 schedule: 'nightly',
44 environment: 'staging'
45 },
46 {
47 name: 'Stress Testing',
48 tests: ['stress-test.spec.ts'],
49 schedule: 'weekly',
50 environment: 'performance'
51 }
52 ];
53 }
54}

Smart Test Selection

1// test/automation/smart-test-runner.ts
2import { execSync } from 'child_process';
3
4export class SmartTestRunner {
5 static getAffectedTests(changedFiles: string[]): string[] {
6 const affectedTests = new Set<string>();
7 
8 changedFiles.forEach(file => {
9 // Dodaj testy dla zmienionych plików
10 const testFile = this.getTestFileForSource(file);
11 if (testFile) {
12 affectedTests.add(testFile);
13 }
14 
15 // Dodaj testy integracyjne jeśli zmieniono API
16 if (this.isApiFile(file)) {
17 this.getIntegrationTests().forEach(test => affectedTests.add(test));
18 }
19 
20 // Dodaj testy E2E jeśli zmieniono kontrolery
21 if (this.isControllerFile(file)) {
22 this.getE2ETests().forEach(test => affectedTests.add(test));
23 }
24 });
25 
26 return Array.from(affectedTests);
27 }
28 
29 static getChangedFiles(): string[] {
30 const gitDiff = execSync('git diff --name-only HEAD~1', { encoding: 'utf8' });
31 return gitDiff.trim().split('
32').filter(Boolean);
33 }
34 
35 private static getTestFileForSource(sourceFile: string): string | null {
36 const testFile = sourceFile.replace(/.ts$/, '.spec.ts');
37 return this.fileExists(testFile) ? testFile : null;
38 }
39 
40 private static isApiFile(file: string): boolean {
41 return file.includes('controller') || file.includes('dto') || file.includes('interface');
42 }
43 
44 private static isControllerFile(file: string): boolean {
45 return file.includes('controller.ts');
46 }
47}

Automated Reporting

Test Results Dashboard

1// test/automation/test-reporter.ts
2export class TestReporter {
3 static generateReport(testResults: TestResult[]): TestReport {
4 const totalTests = testResults.length;
5 const passedTests = testResults.filter(t => t.status === 'passed').length;
6 const failedTests = testResults.filter(t => t.status === 'failed').length;
7 const skippedTests = testResults.filter(t => t.status === 'skipped').length;
8 
9 const coverage = this.calculateCoverage(testResults);
10 const performance = this.analyzePerformance(testResults);
11 
12 return {
13 summary: {
14 total: totalTests,
15 passed: passedTests,
16 failed: failedTests,
17 skipped: skippedTests,
18 successRate: (passedTests / totalTests) * 100
19 },
20 coverage,
21 performance,
22 failedTests: testResults.filter(t => t.status === 'failed'),
23 slowTests: testResults
24 .filter(t => t.duration > 5000)
25 .sort((a, b) => b.duration - a.duration),
26 recommendations: this.generateRecommendations(testResults)
27 };
28 }
29 
30 static async sendSlackNotification(report: TestReport): Promise<void> {
31 const color = report.summary.successRate >= 95 ? 'good' : 
32 report.summary.successRate >= 80 ? 'warning' : 'danger';
33 
34 const message = {
35 text: ' Legionary Legion Test Results',
36 attachments: [{
37 color,
38 fields: [
39 {
40 title: 'Success Rate',
41 value: `${report.summary.successRate.toFixed(1)}%`,
42 short: true
43 },
44 {
45 title: 'Tests',
46 value: `${report.summary.passed}/${report.summary.total}`,
47 short: true
48 },
49 {
50 title: 'Coverage',
51 value: `${report.coverage.statements}%`,
52 short: true
53 },
54 {
55 title: 'Failed Tests',
56 value: report.failedTests.length.toString(),
57 short: true
58 }
59 ]
60 }]
61 };
62 
63 await this.sendToSlack(message);
64 }
65}

Automated Rollback

1# .github/workflows/auto-rollback.yml
2name: Auto Rollback on Failed Tests
3
4on:
5 deployment_status:
6
7jobs:
8 health-check:
9 if: github.event.deployment_status.state == 'success'
10 runs-on: ubuntu-latest
11 
12 steps:
13 - name: Wait for deployment to stabilize
14 run: sleep 60
15 
16 - name: Run health checks
17 id: health-check
18 run: |
19 # Critical endpoints health check
20 curl -f ${{ github.event.deployment.payload.web_url }}/health
21 curl -f ${{ github.event.deployment.payload.web_url }}/api/tributes
22 curl -f ${{ github.event.deployment.payload.web_url }}/api/expeditions
23 
24 - name: Run smoke tests
25 if: steps.health-check.outcome == 'success'
26 run: npm run test:smoke
27 
28 - name: Trigger rollback if tests fail
29 if: failure()
30 uses: actions/github-script@v6
31 with:
32 script: |
33 github.rest.repos.createDeployment({
34 owner: context.repo.owner,
35 repo: context.repo.repo,
36 ref: '${{ github.event.deployment.payload.previous_version }}',
37 environment: '${{ github.event.deployment.environment }}',
38 description: 'Auto rollback due to failed health checks'
39 });

Monitoring i Alerting

Test Performance Monitoring

1// test/automation/performance-monitor.ts
2export class TestPerformanceMonitor {
3 private static readonly PERFORMANCE_THRESHOLDS = {
4 unit: 50, // ms per test
5 integration: 500, // ms per test
6 e2e: 5000, // ms per test
7 total: 300000 // 5 minutes total
8 };
9 
10 static analyzeTestPerformance(results: TestResult[]): PerformanceAlert[] {
11 const alerts: PerformanceAlert[] = [];
12 
13 // Check individual test performance
14 results.forEach(test => {
15 const threshold = this.PERFORMANCE_THRESHOLDS[test.type] || this.PERFORMANCE_THRESHOLDS.unit;
16 
17 if (test.duration > threshold * 2) {
18 alerts.push({
19 type: 'CRITICAL',
20 test: test.name,
21 message: `Test is ${Math.round(test.duration / threshold)}x slower than threshold`,
22 duration: test.duration,
23 threshold
24 });
25 } else if (test.duration > threshold * 1.5) {
26 alerts.push({
27 type: 'WARNING',
28 test: test.name,
29 message: `Test is approaching performance threshold`,
30 duration: test.duration,
31 threshold
32 });
33 }
34 });
35 
36 // Check total test suite duration
37 const totalDuration = results.reduce((sum, test) => sum + test.duration, 0);
38 if (totalDuration > this.PERFORMANCE_THRESHOLDS.total) {
39 alerts.push({
40 type: 'CRITICAL',
41 test: 'Test Suite',
42 message: `Total test duration exceeds maximum allowed time`,
43 duration: totalDuration,
44 threshold: this.PERFORMANCE_THRESHOLDS.total
45 });
46 }
47 
48 return alerts;
49 }
50}

Test Automation to potężny strażnik czuwający nad Twoim rzymskim fortem! Dzięki niemu możesz spać spokojnie, wiedząc że każda zmiana w kodzie jest automatycznie sprawdzana przez najlepszy legion testerów Imperium!

Ir a CodeWorlds