Automatic Test Generation
- Generate tests from code analysis
- Create edge case scenarios
- Build comprehensive test data
- Mock dependencies intelligently
Transform your unit testing practices with AI-powered test generation, intelligent coverage analysis, and self-maintaining test suites. Learn how to achieve comprehensive coverage while reducing test creation and maintenance time by up to 90%.
Unit testing has evolved from a tedious manual process to an intelligent, automated practice that ensures code quality at the most granular level. With AI assistance, you can:
Automatic Test Generation
Intelligent Coverage
Self-Maintaining Tests
Quality Insights
// Original function to testexport class UserService { constructor(private db: Database, private emailService: EmailService) {}
async createUser(userData: CreateUserDto): Promise<User> { // Validate email format if (!this.isValidEmail(userData.email)) { throw new ValidationError('Invalid email format'); }
// Check for existing user const existing = await this.db.users.findOne({ email: userData.email }); if (existing) { throw new ConflictError('User already exists'); }
// Create user const user = await this.db.users.create({ ...userData, id: generateId(), createdAt: new Date(), status: 'pending' });
// Send welcome email await this.emailService.sendWelcome(user.email, user.name);
return user; }}
// AI Prompt for Test GenerationAgent: "Generate comprehensive unit tests for UserService.createUser:- Test all code paths- Include edge cases and error scenarios- Mock all dependencies- Add performance tests- Include test data factories- Use Jest and TypeScript"
// AI generates complete test suite:
# Generate tests for entire moduleclaude "Analyze src/services/UserService.ts and generate:- Unit tests with 100% coverage- Integration tests for database operations- Mock implementations for all dependencies- Test data factories- Performance benchmarks- Error scenario coverage"
# Claude creates:# - src/services/__tests__/UserService.test.ts# - src/services/__tests__/UserService.integration.test.ts# - src/services/__mocks__/Database.ts# - src/services/__mocks__/EmailService.ts# - src/services/__tests__/factories/user.factory.ts
// AI-generated comprehensive test suiteimport { UserService } from '../UserService';import { Database } from '../Database';import { EmailService } from '../EmailService';import { ValidationError, ConflictError } from '../errors';import { createMockDatabase, createMockEmailService } from './mocks';import { UserFactory } from './factories/user.factory';
describe('UserService', () => { let userService: UserService; let mockDb: jest.Mocked<Database>; let mockEmailService: jest.Mocked<EmailService>;
beforeEach(() => { // AI sets up comprehensive mocks mockDb = createMockDatabase(); mockEmailService = createMockEmailService(); userService = new UserService(mockDb, mockEmailService);
// Reset all mocks jest.clearAllMocks(); });
describe('createUser', () => { describe('successful creation', () => { it('should create a user with valid data', async () => { // Arrange const userData = UserFactory.build(); mockDb.users.findOne.mockResolvedValue(null); mockDb.users.create.mockResolvedValue({ ...userData, id: 'generated-id', createdAt: new Date(), status: 'pending' });
// Act const result = await userService.createUser(userData);
// Assert expect(result).toMatchObject({ ...userData, id: expect.any(String), status: 'pending', createdAt: expect.any(Date) });
expect(mockDb.users.findOne).toHaveBeenCalledWith({ email: userData.email }); expect(mockDb.users.create).toHaveBeenCalledWith( expect.objectContaining(userData) ); expect(mockEmailService.sendWelcome).toHaveBeenCalledWith( userData.email, userData.name ); });
it('should generate unique IDs for multiple users', async () => { // AI adds test for ID uniqueness const users = await Promise.all( Array(10).fill(null).map(() => userService.createUser(UserFactory.build()) ) );
const ids = users.map(u => u.id); expect(new Set(ids).size).toBe(10); }); });
describe('validation errors', () => { it.each([ ['invalid-email', 'Invalid email format'], ['@example.com', 'Invalid email format'], ['user@', 'Invalid email format'], ['user..name@example.com', 'Invalid email format'], ])('should reject invalid email: %s', async (email, expectedError) => { const userData = UserFactory.build({ email });
await expect(userService.createUser(userData)) .rejects.toThrow(ValidationError); await expect(userService.createUser(userData)) .rejects.toThrow(expectedError);
expect(mockDb.users.findOne).not.toHaveBeenCalled(); expect(mockDb.users.create).not.toHaveBeenCalled(); expect(mockEmailService.sendWelcome).not.toHaveBeenCalled(); }); });
describe('duplicate user handling', () => { it('should throw ConflictError for existing email', async () => { const existingUser = UserFactory.build(); mockDb.users.findOne.mockResolvedValue(existingUser);
const newUserData = UserFactory.build({ email: existingUser.email });
await expect(userService.createUser(newUserData)) .rejects.toThrow(ConflictError); await expect(userService.createUser(newUserData)) .rejects.toThrow('User already exists');
expect(mockDb.users.create).not.toHaveBeenCalled(); expect(mockEmailService.sendWelcome).not.toHaveBeenCalled(); }); });
describe('error handling', () => { it('should handle database errors gracefully', async () => { mockDb.users.findOne.mockRejectedValue( new Error('Database connection failed') );
await expect(userService.createUser(UserFactory.build())) .rejects.toThrow('Database connection failed'); });
it('should not send email if user creation fails', async () => { mockDb.users.findOne.mockResolvedValue(null); mockDb.users.create.mockRejectedValue( new Error('Creation failed') );
await expect(userService.createUser(UserFactory.build())) .rejects.toThrow('Creation failed');
expect(mockEmailService.sendWelcome).not.toHaveBeenCalled(); });
it('should handle email service failures', async () => { mockDb.users.findOne.mockResolvedValue(null); const createdUser = UserFactory.build(); mockDb.users.create.mockResolvedValue(createdUser); mockEmailService.sendWelcome.mockRejectedValue( new Error('Email service down') );
// User should still be created even if email fails const result = await userService.createUser(UserFactory.build()); expect(result).toBeDefined(); }); });
describe('performance', () => { it('should create user within acceptable time', async () => { const startTime = Date.now(); await userService.createUser(UserFactory.build()); const duration = Date.now() - startTime;
expect(duration).toBeLessThan(100); // 100ms threshold });
it('should handle concurrent user creation', async () => { const userData = Array(100).fill(null).map(() => UserFactory.build() );
const results = await Promise.all( userData.map(data => userService.createUser(data)) );
expect(results).toHaveLength(100); expect(mockDb.users.create).toHaveBeenCalledTimes(100); }); }); });});
// AI generates property-based testsimport * as fc from 'fast-check';
describe('UserService - Property Tests', () => { it('should always create valid users regardless of input', () => { fc.assert( fc.property( // AI generates comprehensive arbitraries fc.record({ name: fc.string({ minLength: 1, maxLength: 100 }), email: fc.emailAddress(), age: fc.integer({ min: 0, max: 150 }), preferences: fc.dictionary(fc.string(), fc.jsonValue()) }), async (userData) => { const result = await userService.createUser(userData);
// Properties that should always hold expect(result.id).toBeDefined(); expect(result.createdAt).toBeInstanceOf(Date); expect(result.email).toBe(userData.email.toLowerCase()); expect(result.status).toBe('pending'); } ) ); });});
// AI configures and runs mutation testingmodule.exports = { mutator: 'typescript', packageManager: 'npm', reporters: ['html', 'clear-text', 'progress'], testRunner: 'jest', transpilers: ['typescript'], coverageAnalysis: 'perTest', mutate: ['src/**/*.ts', '!src/**/*.test.ts'],
// AI-optimized mutation testing thresholds: { high: 90, low: 80, break: 75 },
// AI suggests which mutations to prioritize mutationLevels: [ 'ConditionalExpression', 'LogicalOperator', 'StringLiteral', 'BooleanLiteral' ]};
// AI enhances snapshot testingdescribe('Component Rendering', () => { it('should match snapshot with dynamic data normalization', () => { const component = render(<UserProfile user={testUser} />);
// AI normalizes dynamic values const snapshot = normalizeSnapshot(component.asFragment(), { timestamps: 'TIMESTAMP', ids: 'ID', randomValues: 'RANDOM' });
expect(snapshot).toMatchSnapshot(); });
// AI detects meaningful vs. trivial snapshot changes it('should alert only on significant changes', () => { const aiAnalysis = analyzeSnapshotDiff( previousSnapshot, currentSnapshot );
if (aiAnalysis.isSignificant) { console.warn('Significant UI change detected:', aiAnalysis.summary); } });});
// AI generates realistic test dataclass UserFactory { static build(overrides?: Partial<User>): User { return { id: faker.datatype.uuid(), email: faker.internet.email().toLowerCase(), name: faker.name.fullName(), age: faker.datatype.number({ min: 18, max: 80 }), address: { street: faker.address.streetAddress(), city: faker.address.city(), country: faker.address.country(), zipCode: faker.address.zipCode() }, preferences: this.generateRealisticPreferences(), createdAt: faker.date.recent(), ...overrides }; }
static generateRealisticPreferences() { // AI creates realistic user preferences return { notifications: { email: faker.datatype.boolean({ probability: 0.7 }), sms: faker.datatype.boolean({ probability: 0.3 }), push: faker.datatype.boolean({ probability: 0.5 }) }, theme: faker.helpers.arrayElement(['light', 'dark', 'auto']), language: faker.helpers.arrayElement(['en', 'es', 'fr', 'de']), timezone: faker.address.timeZone() }; }
static buildList(count: number): User[] { // AI ensures diverse test data return Array(count).fill(null).map((_, index) => this.build({ // Ensure some variety in test data age: 18 + (index % 62), preferences: index % 3 === 0 ? { notifications: { email: true } } : undefined }) ); }}
// AI analyzes and improves test coverageclass CoverageOptimizer { async analyzeCoverage(testResults: TestResults): Promise<CoverageReport> { const uncoveredPaths = this.findUncoveredPaths(testResults); const suggestions = await this.ai.generateTestSuggestions(uncoveredPaths);
return { currentCoverage: testResults.coverage, uncoveredPaths, suggestions, prioritizedTests: this.prioritizeByRisk(suggestions), estimatedImprovement: this.calculatePotentialCoverage(suggestions) }; }
generateMissingTests(report: CoverageReport): TestCase[] { return report.suggestions.map(suggestion => ({ description: suggestion.description, code: this.ai.generateTestCode(suggestion), priority: suggestion.riskScore, estimatedCoverage: suggestion.coverageGain })); }}
// AI maintains tests automaticallyclass TestMaintainer { async fixBrokenTest(test: TestCase, error: TestError): Promise<TestCase> { const diagnosis = await this.ai.diagnoseFailure(test, error);
switch (diagnosis.type) { case 'ASSERTION_OUTDATED': return this.updateAssertions(test, diagnosis.newExpectations);
case 'MOCK_MISMATCH': return this.updateMocks(test, diagnosis.actualCalls);
case 'SCHEMA_CHANGE': return this.adaptToSchemaChange(test, diagnosis.schemaUpdate);
case 'TIMING_ISSUE': return this.addProperWaits(test, diagnosis.timingAnalysis);
default: return this.flagForManualReview(test, diagnosis); } }}
// Good: Focused, clear testsit('should calculate discount correctly for premium users', () => { const user = UserFactory.build({ tier: 'premium' }); const discount = calculateDiscount(user, 100); expect(discount).toBe(20); // 20% for premium});
// Good: Descriptive test namesit('should throw ValidationError when email contains spaces', () => { expect(() => validateEmail('user @example.com')) .toThrow(ValidationError);});
// Good: Testing behavior, not implementationit('should notify user after successful purchase', async () => { await purchaseService.completePurchase(order); expect(notificationService.send).toHaveBeenCalledWith( expect.objectContaining({ type: 'purchase_complete' }) );});
// Bad: Testing implementation detailsit('should call internal method', () => { service.publicMethod(); expect(service._privateMethod).toHaveBeenCalled(); // Don't test privates});
// Bad: Multiple assertions without clear purposeit('should work', () => { const result = service.process(data); expect(result).toBeDefined(); expect(result.id).toBeTruthy(); expect(result.data).toEqual(expect.anything()); // What are we actually testing?});
// Bad: Overly complex setupit('should handle edge case', () => { // 50 lines of setup... // Actual test is 2 lines});
Metric | Target | AI Enhancement |
---|---|---|
Test Generation Speed | 15x faster than manual | Natural language prompts |
Coverage Achievement | >95% automatically | AI identifies gaps |
Maintenance Reduction | 90% less time | Self-healing tests |
Bug Detection | 75% more edge cases | AI pattern recognition |
Developer Satisfaction | >90% positive feedback | Reduced cognitive load |
Time to Market | 40% faster releases | Faster validation cycles |
Coverage Gates
Reliability Gates
# AI generates pytest testsimport pytestfrom unittest.mock import Mock, patchfrom user_service import UserServicefrom factories import UserFactory
class TestUserService: @pytest.fixture def service(self): """AI creates comprehensive fixtures""" db = Mock() email_service = Mock() return UserService(db, email_service)
@pytest.mark.parametrize("email,expected", [ ("valid@example.com", True), ("invalid.email", False), ("@example.com", False), ("user@", False), ]) def test_email_validation(self, service, email, expected): """AI generates parameterized tests""" assert service.is_valid_email(email) == expected
@pytest.mark.asyncio async def test_create_user_success(self, service): """AI handles async testing""" user_data = UserFactory.build() service.db.find_one.return_value = None service.db.create.return_value = user_data
result = await service.create_user(user_data)
assert result.email == user_data["email"] service.email_service.send_welcome.assert_called_once()
// AI generates JUnit 5 tests@ExtendWith(MockitoExtension.class)class UserServiceTest {
@Mock private Database database; @Mock private EmailService emailService; @InjectMocks private UserService userService;
@ParameterizedTest @ValueSource(strings = { "invalid-email", "@example.com", "user@", "user..name@example.com" }) void shouldRejectInvalidEmails(String email) { // AI generates comprehensive parameterized tests var userData = UserFactory.build() .withEmail(email);
assertThrows( ValidationException.class, () -> userService.createUser(userData) );
verifyNoInteractions(database, emailService); }
@Test @DisplayName("Should create user with valid data") void createUser_withValidData_success() { // AI creates readable, well-structured tests var userData = UserFactory.build(); when(database.findByEmail(userData.getEmail())) .thenReturn(Optional.empty()); when(database.save(any(User.class))) .thenReturn(userData);
var result = userService.createUser(userData);
assertAll( () -> assertNotNull(result.getId()), () -> assertEquals("pending", result.getStatus()), () -> assertNotNull(result.getCreatedAt()) );
verify(emailService).sendWelcome( userData.getEmail(), userData.getName() ); }}