mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
2e8642030b
🎯 Test Suite Stabilization - 94.2% Pass Rate Achieved! This release represents a major quality milestone with systematic test stabilization that increased the unit test pass rate from 71.1% (619/870) to 94.2% (903/959), exceeding the 90% goal set in GitHub issue #33. Major Changes: - Fixed all TypeScript compilation errors blocking release - Created batched integration test script to prevent OOM crashes - Documented integration test memory leak root cause (issue #35) - Enhanced mock infrastructure for better test reliability - Updated release verification policies in CLAUDE.md TypeScript Fixes: - Fixed TestGeneratorAgent AgentCapability structure (4 errors) - Rewrote Database mock with proper type casting (36 methods) - Rewrote LearningEngine mock with proper type casting - Excluded __mocks__ from TypeScript compilation Test Infrastructure: - Created scripts/test-integration-batched.sh for safe execution - Batches 46 integration tests (5 files at a time) - Prevents workspace crashes in constrained environments - Updated package.json test:integration to use batched script Memory Leak Investigation: - Root cause: MemoryManager setInterval leak (138 timers) - Missing cleanup in 31 of 46 integration tests - Database connection pool exhaustion (23 instances) - Documented in GitHub issue #35 for v1.4.4 fix Release Verification: - aqe init: 19 agents, 34 skills, 8 commands ✅ - Databases: memory.db (221KB), patterns.db (155KB) ✅ - MCP interface: 54 tools functional ✅ - Fleet startup: 5 agents running successfully ✅ Files Changed: - Modified: 40 files (tests, mocks, core agents) - New: 2 files (batched script, LearningEngine mock) - Version: 1.4.2 → 1.4.3 Closes #33 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
307 lines
11 KiB
TypeScript
307 lines
11 KiB
TypeScript
// Mock Logger to prevent undefined errors
|
|
jest.mock('@utils/Logger', () => ({
|
|
Logger: {
|
|
getInstance: jest.fn(() => ({
|
|
info: jest.fn(),
|
|
error: jest.fn(),
|
|
warn: jest.fn(),
|
|
debug: jest.fn(),
|
|
log: jest.fn()
|
|
}))
|
|
}
|
|
}));
|
|
|
|
import { StatisticalAnalysis } from '../../../src/learning/StatisticalAnalysis';
|
|
import { TestResult } from '../../../src/learning/types';
|
|
|
|
describe('StatisticalAnalysis', () => {
|
|
describe('calculatePassRate', () => {
|
|
it('should return 0 for empty results', () => {
|
|
const passRate = StatisticalAnalysis.calculatePassRate([]);
|
|
expect(passRate).toBe(0);
|
|
});
|
|
|
|
it('should calculate 100% pass rate for all passing tests', () => {
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: Date.now() },
|
|
{ name: 'test2', passed: true, duration: 150, timestamp: Date.now() },
|
|
{ name: 'test3', passed: true, duration: 120, timestamp: Date.now() }
|
|
];
|
|
|
|
const passRate = StatisticalAnalysis.calculatePassRate(results);
|
|
expect(passRate).toBe(1);
|
|
});
|
|
|
|
it('should calculate 50% pass rate for half passing tests', () => {
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: Date.now() },
|
|
{ name: 'test2', passed: false, duration: 150, timestamp: Date.now() }
|
|
];
|
|
|
|
const passRate = StatisticalAnalysis.calculatePassRate(results);
|
|
expect(passRate).toBe(0.5);
|
|
});
|
|
|
|
it('should calculate 0% pass rate for all failing tests', () => {
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: false, duration: 100, timestamp: Date.now() },
|
|
{ name: 'test2', passed: false, duration: 150, timestamp: Date.now() }
|
|
];
|
|
|
|
const passRate = StatisticalAnalysis.calculatePassRate(results);
|
|
expect(passRate).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('calculateVariance', () => {
|
|
it('should return 0 for less than 2 results', () => {
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: Date.now() }
|
|
];
|
|
|
|
const variance = StatisticalAnalysis.calculateVariance(results);
|
|
expect(variance).toBe(0);
|
|
});
|
|
|
|
it('should calculate variance correctly for uniform durations', () => {
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: Date.now() },
|
|
{ name: 'test2', passed: true, duration: 100, timestamp: Date.now() },
|
|
{ name: 'test3', passed: true, duration: 100, timestamp: Date.now() }
|
|
];
|
|
|
|
const variance = StatisticalAnalysis.calculateVariance(results);
|
|
expect(variance).toBe(0);
|
|
});
|
|
|
|
it('should calculate variance correctly for varied durations', () => {
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: Date.now() },
|
|
{ name: 'test2', passed: true, duration: 200, timestamp: Date.now() },
|
|
{ name: 'test3', passed: true, duration: 150, timestamp: Date.now() }
|
|
];
|
|
|
|
const variance = StatisticalAnalysis.calculateVariance(results);
|
|
expect(variance).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('calculateConfidence', () => {
|
|
it('should return 0 for empty results', () => {
|
|
const confidence = StatisticalAnalysis.calculateConfidence([]);
|
|
expect(confidence).toBe(0);
|
|
});
|
|
|
|
it('should return higher confidence for more samples with low variance', () => {
|
|
const manyConsistentResults: TestResult[] = Array.from({ length: 100 }, (_, i) => ({
|
|
name: `test${i}`,
|
|
passed: true,
|
|
duration: 100 + Math.random() * 5, // Low variance
|
|
timestamp: Date.now()
|
|
}));
|
|
|
|
const fewResults: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: Date.now() },
|
|
{ name: 'test2', passed: true, duration: 105, timestamp: Date.now() }
|
|
];
|
|
|
|
const highConfidence = StatisticalAnalysis.calculateConfidence(manyConsistentResults);
|
|
const lowConfidence = StatisticalAnalysis.calculateConfidence(fewResults);
|
|
|
|
expect(highConfidence).toBeGreaterThan(lowConfidence);
|
|
});
|
|
|
|
it('should return confidence between 0 and 1', () => {
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: Date.now() },
|
|
{ name: 'test2', passed: true, duration: 150, timestamp: Date.now() },
|
|
{ name: 'test3', passed: false, duration: 200, timestamp: Date.now() }
|
|
];
|
|
|
|
const confidence = StatisticalAnalysis.calculateConfidence(results);
|
|
expect(confidence).toBeGreaterThanOrEqual(0);
|
|
expect(confidence).toBeLessThanOrEqual(1);
|
|
});
|
|
});
|
|
|
|
describe('calculateMetrics', () => {
|
|
it('should return zero metrics for empty values', () => {
|
|
const metrics = StatisticalAnalysis.calculateMetrics([]);
|
|
|
|
expect(metrics.mean).toBe(0);
|
|
expect(metrics.median).toBe(0);
|
|
expect(metrics.variance).toBe(0);
|
|
expect(metrics.stdDev).toBe(0);
|
|
expect(metrics.min).toBe(0);
|
|
expect(metrics.max).toBe(0);
|
|
expect(metrics.outliers).toEqual([]);
|
|
});
|
|
|
|
it('should calculate metrics correctly for simple dataset', () => {
|
|
const values = [10, 20, 30, 40, 50];
|
|
const metrics = StatisticalAnalysis.calculateMetrics(values);
|
|
|
|
expect(metrics.mean).toBe(30);
|
|
expect(metrics.median).toBe(30);
|
|
expect(metrics.min).toBe(10);
|
|
expect(metrics.max).toBe(50);
|
|
expect(metrics.variance).toBeGreaterThan(0);
|
|
expect(metrics.stdDev).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should identify outliers in dataset', () => {
|
|
const values = [10, 12, 11, 13, 12, 100]; // 100 is an outlier
|
|
const metrics = StatisticalAnalysis.calculateMetrics(values);
|
|
|
|
expect(metrics.outliers.length).toBeGreaterThan(0);
|
|
expect(metrics.outliers).toContain(100);
|
|
});
|
|
|
|
it('should calculate median correctly for even number of values', () => {
|
|
const values = [10, 20, 30, 40];
|
|
const metrics = StatisticalAnalysis.calculateMetrics(values);
|
|
|
|
expect(metrics.median).toBe(25); // (20 + 30) / 2
|
|
});
|
|
|
|
it('should calculate median correctly for odd number of values', () => {
|
|
const values = [10, 20, 30];
|
|
const metrics = StatisticalAnalysis.calculateMetrics(values);
|
|
|
|
expect(metrics.median).toBe(20);
|
|
});
|
|
});
|
|
|
|
describe('isFlakyCandidate', () => {
|
|
it('should identify flaky test with intermittent failures', () => {
|
|
const passRate = 0.5; // 50% pass rate
|
|
const variance = 500;
|
|
|
|
const isFlaky = StatisticalAnalysis.isFlakyCandidate(passRate, variance);
|
|
expect(isFlaky).toBe(true);
|
|
});
|
|
|
|
it('should not identify stable passing test as flaky', () => {
|
|
const passRate = 0.99; // 99% pass rate
|
|
const variance = 100; // Low variance
|
|
|
|
const isFlaky = StatisticalAnalysis.isFlakyCandidate(passRate, variance);
|
|
expect(isFlaky).toBe(false);
|
|
});
|
|
|
|
it('should identify test with low pass rate and high variance as flaky', () => {
|
|
const passRate = 0.85; // 85% pass rate
|
|
const variance = 2000; // High variance
|
|
|
|
const isFlaky = StatisticalAnalysis.isFlakyCandidate(passRate, variance);
|
|
expect(isFlaky).toBe(true);
|
|
});
|
|
|
|
it('should not identify consistently failing test as flaky', () => {
|
|
const passRate = 0.0; // 0% pass rate
|
|
const variance = 100;
|
|
|
|
const isFlaky = StatisticalAnalysis.isFlakyCandidate(passRate, variance);
|
|
expect(isFlaky).toBe(false);
|
|
});
|
|
|
|
it('should identify test with pass rate in flaky range', () => {
|
|
const passRate = 0.3; // 30% pass rate (in 20-80% range)
|
|
const variance = 500;
|
|
|
|
const isFlaky = StatisticalAnalysis.isFlakyCandidate(passRate, variance);
|
|
expect(isFlaky).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('detectTrend', () => {
|
|
it('should return 0 for insufficient data', () => {
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: Date.now() }
|
|
];
|
|
|
|
const trend = StatisticalAnalysis.detectTrend(results);
|
|
expect(trend).toBe(0);
|
|
});
|
|
|
|
it('should detect improving trend', () => {
|
|
const now = Date.now();
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: false, duration: 100, timestamp: now - 3000 },
|
|
{ name: 'test2', passed: false, duration: 100, timestamp: now - 2000 },
|
|
{ name: 'test3', passed: true, duration: 100, timestamp: now - 1000 },
|
|
{ name: 'test4', passed: true, duration: 100, timestamp: now }
|
|
];
|
|
|
|
const trend = StatisticalAnalysis.detectTrend(results);
|
|
expect(trend).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should detect degrading trend', () => {
|
|
const now = Date.now();
|
|
const results: TestResult[] = [
|
|
{ name: 'test1', passed: true, duration: 100, timestamp: now - 3000 },
|
|
{ name: 'test2', passed: true, duration: 100, timestamp: now - 2000 },
|
|
{ name: 'test3', passed: false, duration: 100, timestamp: now - 1000 },
|
|
{ name: 'test4', passed: false, duration: 100, timestamp: now }
|
|
];
|
|
|
|
const trend = StatisticalAnalysis.detectTrend(results);
|
|
expect(trend).toBeLessThan(0);
|
|
});
|
|
});
|
|
|
|
describe('identifyOutliers', () => {
|
|
it('should return empty array for insufficient data', () => {
|
|
const outliers = StatisticalAnalysis.identifyOutliers([1, 2]);
|
|
expect(outliers).toEqual([]);
|
|
});
|
|
|
|
it('should identify outliers using IQR method', () => {
|
|
const values = [10, 12, 11, 13, 12, 11, 100, 10, 12]; // 100 is an outlier
|
|
const outliers = StatisticalAnalysis.identifyOutliers(values);
|
|
|
|
expect(outliers.length).toBeGreaterThan(0);
|
|
expect(outliers).toContain(100);
|
|
});
|
|
|
|
it('should not identify outliers in uniform data', () => {
|
|
const values = [10, 10, 10, 10, 10];
|
|
const outliers = StatisticalAnalysis.identifyOutliers(values);
|
|
|
|
expect(outliers).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe('calculateCorrelation', () => {
|
|
it('should return 0 for empty or mismatched arrays', () => {
|
|
expect(StatisticalAnalysis.calculateCorrelation([], [])).toBe(0);
|
|
expect(StatisticalAnalysis.calculateCorrelation([1, 2], [1])).toBe(0);
|
|
});
|
|
|
|
it('should calculate perfect positive correlation', () => {
|
|
const x = [1, 2, 3, 4, 5];
|
|
const y = [2, 4, 6, 8, 10];
|
|
|
|
const correlation = StatisticalAnalysis.calculateCorrelation(x, y);
|
|
expect(correlation).toBeCloseTo(1, 5);
|
|
});
|
|
|
|
it('should calculate perfect negative correlation', () => {
|
|
const x = [1, 2, 3, 4, 5];
|
|
const y = [10, 8, 6, 4, 2];
|
|
|
|
const correlation = StatisticalAnalysis.calculateCorrelation(x, y);
|
|
expect(correlation).toBeCloseTo(-1, 5);
|
|
});
|
|
|
|
it('should calculate no correlation', () => {
|
|
const x = [1, 2, 3, 4, 5];
|
|
const y = [5, 3, 5, 3, 5]; // Random pattern
|
|
|
|
const correlation = StatisticalAnalysis.calculateCorrelation(x, y);
|
|
expect(Math.abs(correlation)).toBeLessThan(1);
|
|
});
|
|
});
|
|
});
|