AI-Assisted Testing Framework Tutorials
Learn to leverage AI tools for comprehensive testing while maintaining quality standards and test reliability. These tutorials cover test generation, validation, maintenance, and advanced testing strategies using AI assistance.
AI-Assisted Testing Overview
Core Principles:
- AI as Test Accelerator: Use AI to generate comprehensive test suites rapidly
- Human Validation: Every AI-generated test is reviewed for correctness and value
- Quality Over Quantity: Focus on meaningful tests that provide business value
- Maintenance Minded: Generate tests that are easy to maintain and update
- Strategic Coverage: Use AI to identify testing gaps and edge cases
Tutorial 1: Unit Test Generation with AI
Objective
Learn to generate comprehensive unit tests using AI assistance while maintaining test quality and coverage standards.
Prerequisites
- Basic understanding of testing concepts
- Familiarity with your chosen testing framework (Jest, Vitest, etc.)
- Access to AI coding assistant (Cursor, GitHub Copilot, ChatGPT, etc.)
Step 1: Setting Up AI Context for Testing
Context Template for AI Testing:
# AI Testing Context
## Project Information
**Framework**: {{TestingFramework}} (Jest/Vitest/Mocha)
**Language**: {{Language}} (TypeScript/JavaScript)
**Test Style**: {{TestStyle}} (Arrange-Act-Assert/Given-When-Then)
**Mocking Library**: {{MockingLibrary}} (jest.mock/Sinon/MSW)
## Testing Standards
- Minimum 80% code coverage
- Test all public methods and edge cases
- Use descriptive test names
- Follow AAA (Arrange, Act, Assert) pattern
- Mock external dependencies
- Test both success and error scenarios
## Code to Test
```{{language}}
{{YourCodeHere}}
Please generate comprehensive unit tests following these requirements:
- Test all public methods
- Cover edge cases and error conditions
- Use proper mocking for dependencies
- Include setup and teardown as needed
- Follow naming conventions:
describe('ClassName', () => { it('should...', () => {}) })
### Step 2: Generating Basic Unit Tests
**Example: Testing a User Service**
*Code to test:*
```typescript
// services/user.service.ts
import { UserRepository } from '../repositories/user.repository';
import { User, CreateUserDto, UpdateUserDto } from '../types/user.types';
import { ValidationError, NotFoundError } from '../errors/custom.errors';
import { EmailValidator } from '../utils/email.validator';
import { PasswordHasher } from '../utils/password.hasher';
export class UserService {
constructor(
private userRepository: UserRepository,
private emailValidator: EmailValidator,
private passwordHasher: PasswordHasher
) {}
async createUser(userData: CreateUserDto): Promise<User> {
// Validate email format
if (!this.emailValidator.isValid(userData.email)) {
throw new ValidationError('Invalid email format');
}
// Check if user already exists
const existingUser = await this.userRepository.findByEmail(userData.email);
if (existingUser) {
throw new ValidationError('User already exists');
}
// Hash password
const hashedPassword = await this.passwordHasher.hash(userData.password);
// Create user
const newUser = await this.userRepository.create({
...userData,
password: hashedPassword,
});
return newUser;
}
async getUserById(id: string): Promise<User> {
const user = await this.userRepository.findById(id);
if (!user) {
throw new NotFoundError('User not found');
}
return user;
}
async updateUser(id: string, updateData: UpdateUserDto): Promise<User> {
const user = await this.getUserById(id);
if (updateData.email && !this.emailValidator.isValid(updateData.email)) {
throw new ValidationError('Invalid email format');
}
if (updateData.password) {
updateData.password = await this.passwordHasher.hash(updateData.password);
}
return await this.userRepository.update(id, updateData);
}
}
AI-Generated Test Suite:
// tests/services/user.service.test.ts
import { UserService } from '../../services/user.service';
import { UserRepository } from '../../repositories/user.repository';
import { EmailValidator } from '../../utils/email.validator';
import { PasswordHasher } from '../../utils/password.hasher';
import { ValidationError, NotFoundError } from '../../errors/custom.errors';
import { CreateUserDto, UpdateUserDto, User } from '../../types/user.types';
// Mock dependencies
jest.mock('../../repositories/user.repository');
jest.mock('../../utils/email.validator');
jest.mock('../../utils/password.hasher');
describe('UserService', () => {
let userService: UserService;
let mockUserRepository: jest.Mocked<UserRepository>;
let mockEmailValidator: jest.Mocked<EmailValidator>;
let mockPasswordHasher: jest.Mocked<PasswordHasher>;
beforeEach(() => {
// Reset all mocks
jest.clearAllMocks();
// Create mocked instances
mockUserRepository = new UserRepository() as jest.Mocked<UserRepository>;
mockEmailValidator = new EmailValidator() as jest.Mocked<EmailValidator>;
mockPasswordHasher = new PasswordHasher() as jest.Mocked<PasswordHasher>;
// Initialize service with mocks
userService = new UserService(
mockUserRepository,
mockEmailValidator,
mockPasswordHasher
);
});
describe('createUser', () => {
const validUserData: CreateUserDto = {
email: 'test@example.com',
password: 'password123',
firstName: 'John',
lastName: 'Doe',
};
it('should create user successfully with valid data', async () => {
// Arrange
const hashedPassword = 'hashed_password_123';
const createdUser: User = {
id: '1',
...validUserData,
password: hashedPassword,
createdAt: new Date(),
updatedAt: new Date(),
};
mockEmailValidator.isValid.mockReturnValue(true);
mockUserRepository.findByEmail.mockResolvedValue(null);
mockPasswordHasher.hash.mockResolvedValue(hashedPassword);
mockUserRepository.create.mockResolvedValue(createdUser);
// Act
const result = await userService.createUser(validUserData);
// Assert
expect(mockEmailValidator.isValid).toHaveBeenCalledWith(validUserData.email);
expect(mockUserRepository.findByEmail).toHaveBeenCalledWith(validUserData.email);
expect(mockPasswordHasher.hash).toHaveBeenCalledWith(validUserData.password);
expect(mockUserRepository.create).toHaveBeenCalledWith({
...validUserData,
password: hashedPassword,
});
expect(result).toEqual(createdUser);
});
it('should throw ValidationError for invalid email', async () => {
// Arrange
mockEmailValidator.isValid.mockReturnValue(false);
// Act & Assert
await expect(userService.createUser(validUserData))
.rejects
.toThrow(new ValidationError('Invalid email format'));
expect(mockEmailValidator.isValid).toHaveBeenCalledWith(validUserData.email);
expect(mockUserRepository.findByEmail).not.toHaveBeenCalled();
});
it('should throw ValidationError if user already exists', async () => {
// Arrange
const existingUser: User = {
id: '1',
...validUserData,
createdAt: new Date(),
updatedAt: new Date(),
};
mockEmailValidator.isValid.mockReturnValue(true);
mockUserRepository.findByEmail.mockResolvedValue(existingUser);
// Act & Assert
await expect(userService.createUser(validUserData))
.rejects
.toThrow(new ValidationError('User already exists'));
expect(mockUserRepository.findByEmail).toHaveBeenCalledWith(validUserData.email);
expect(mockPasswordHasher.hash).not.toHaveBeenCalled();
});
});
describe('getUserById', () => {
it('should return user when found', async () => {
// Arrange
const userId = '1';
const user: User = {
id: userId,
email: 'test@example.com',
firstName: 'John',
lastName: 'Doe',
password: 'hashed_password',
createdAt: new Date(),
updatedAt: new Date(),
};
mockUserRepository.findById.mockResolvedValue(user);
// Act
const result = await userService.getUserById(userId);
// Assert
expect(mockUserRepository.findById).toHaveBeenCalledWith(userId);
expect(result).toEqual(user);
});
it('should throw NotFoundError when user not found', async () => {
// Arrange
const userId = 'nonexistent';
mockUserRepository.findById.mockResolvedValue(null);
// Act & Assert
await expect(userService.getUserById(userId))
.rejects
.toThrow(new NotFoundError('User not found'));
expect(mockUserRepository.findById).toHaveBeenCalledWith(userId);
});
});
describe('updateUser', () => {
const userId = '1';
const existingUser: User = {
id: userId,
email: 'old@example.com',
firstName: 'John',
lastName: 'Doe',
password: 'old_hashed_password',
createdAt: new Date(),
updatedAt: new Date(),
};
beforeEach(() => {
mockUserRepository.findById.mockResolvedValue(existingUser);
});
it('should update user successfully', async () => {
// Arrange
const updateData: UpdateUserDto = {
firstName: 'Jane',
lastName: 'Smith',
};
const updatedUser: User = {
...existingUser,
...updateData,
};
mockUserRepository.update.mockResolvedValue(updatedUser);
// Act
const result = await userService.updateUser(userId, updateData);
// Assert
expect(mockUserRepository.findById).toHaveBeenCalledWith(userId);
expect(mockUserRepository.update).toHaveBeenCalledWith(userId, updateData);
expect(result).toEqual(updatedUser);
});
it('should hash password when updating password', async () => {
// Arrange
const updateData: UpdateUserDto = {
password: 'new_password_123',
};
const hashedNewPassword = 'new_hashed_password';
const updatedUser: User = {
...existingUser,
password: hashedNewPassword,
};
mockPasswordHasher.hash.mockResolvedValue(hashedNewPassword);
mockUserRepository.update.mockResolvedValue(updatedUser);
// Act
const result = await userService.updateUser(userId, updateData);
// Assert
expect(mockPasswordHasher.hash).toHaveBeenCalledWith(updateData.password);
expect(mockUserRepository.update).toHaveBeenCalledWith(userId, {
password: hashedNewPassword,
});
expect(result).toEqual(updatedUser);
});
it('should validate email when updating email', async () => {
// Arrange
const updateData: UpdateUserDto = {
email: 'newemail@example.com',
};
const updatedUser: User = {
...existingUser,
email: updateData.email,
};
mockEmailValidator.isValid.mockReturnValue(true);
mockUserRepository.update.mockResolvedValue(updatedUser);
// Act
const result = await userService.updateUser(userId, updateData);
// Assert
expect(mockEmailValidator.isValid).toHaveBeenCalledWith(updateData.email);
expect(mockUserRepository.update).toHaveBeenCalledWith(userId, updateData);
expect(result).toEqual(updatedUser);
});
it('should throw ValidationError for invalid email update', async () => {
// Arrange
const updateData: UpdateUserDto = {
email: 'invalid-email',
};
mockEmailValidator.isValid.mockReturnValue(false);
// Act & Assert
await expect(userService.updateUser(userId, updateData))
.rejects
.toThrow(new ValidationError('Invalid email format'));
expect(mockEmailValidator.isValid).toHaveBeenCalledWith(updateData.email);
expect(mockUserRepository.update).not.toHaveBeenCalled();
});
});
});
Step 3: Test Quality Review
AI-Generated Test Review Checklist:
# AI Test Quality Review
## Coverage Analysis
- [ ] All public methods tested
- [ ] Error cases covered
- [ ] Edge cases identified and tested
- [ ] Success paths validated
## Test Quality
- [ ] Tests are independent and isolated
- [ ] Proper arrange-act-assert structure
- [ ] Descriptive test names
- [ ] Appropriate use of mocks and stubs
- [ ] No implementation details tested
## Maintainability
- [ ] Tests are readable and understandable
- [ ] Mock setup is clear and consistent
- [ ] Test data is realistic and meaningful
- [ ] Tests can be easily modified when requirements change
Tutorial 2: Integration Test Generation
Objective
Generate comprehensive integration tests that validate system components working together.
Step 1: Database Integration Tests
AI Prompt for Database Integration Tests:
Generate integration tests for a REST API with database interactions. Requirements:
## Test Environment
- **Framework**: Jest with Supertest
- **Database**: PostgreSQL with test database
- **ORM**: TypeORM
- **API**: Express.js REST API
## Test Structure
- Setup test database before tests
- Clean database between tests
- Test actual HTTP requests and responses
- Validate database state changes
- Test error scenarios and edge cases
## API Endpoints to Test
POST /api/users - Create user
GET /api/users/:id - Get user by ID
PUT /api/users/:id - Update user
DELETE /api/users/:id - Delete user
GET /api/users - List users with pagination
Please generate comprehensive integration tests with proper setup, teardown, and realistic test scenarios.
AI-Generated Integration Test Suite:
// tests/integration/user.api.test.ts
import request from 'supertest';
import { DataSource } from 'typeorm';
import { app } from '../../src/app';
import { AppDataSource } from '../../src/config/database';
import { User } from '../../src/entities/user.entity';
import { CreateUserDto, UpdateUserDto } from '../../src/types/user.types';
describe('User API Integration Tests', () => {
let dataSource: DataSource;
let userRepository: Repository<User>;
beforeAll(async () => {
// Initialize test database connection
dataSource = await AppDataSource.initialize();
userRepository = dataSource.getRepository(User);
});
afterAll(async () => {
// Close database connection
await dataSource.destroy();
});
beforeEach(async () => {
// Clean database before each test
await userRepository.clear();
});
describe('POST /api/users', () => {
const validUserData: CreateUserDto = {
email: 'test@example.com',
password: 'password123',
firstName: 'John',
lastName: 'Doe',
};
it('should create user successfully', async () => {
// Act
const response = await request(app)
.post('/api/users')
.send(validUserData)
.expect(201);
// Assert response
expect(response.body.success).toBe(true);
expect(response.body.data).toMatchObject({
email: validUserData.email,
firstName: validUserData.firstName,
lastName: validUserData.lastName,
});
expect(response.body.data.password).toBeUndefined(); // Password should not be returned
expect(response.body.data.id).toBeDefined();
// Assert database state
const userInDb = await userRepository.findOne({
where: { email: validUserData.email },
});
expect(userInDb).toBeTruthy();
expect(userInDb.email).toBe(validUserData.email);
expect(userInDb.password).not.toBe(validUserData.password); // Should be hashed
});
it('should return 400 for invalid email', async () => {
const invalidUserData = {
...validUserData,
email: 'invalid-email',
};
const response = await request(app)
.post('/api/users')
.send(invalidUserData)
.expect(400);
expect(response.body.success).toBe(false);
expect(response.body.message).toContain('email');
// Assert no user created in database
const userCount = await userRepository.count();
expect(userCount).toBe(0);
});
it('should return 409 for duplicate email', async () => {
// Create initial user
await request(app)
.post('/api/users')
.send(validUserData)
.expect(201);
// Try to create duplicate
const response = await request(app)
.post('/api/users')
.send(validUserData)
.expect(409);
expect(response.body.success).toBe(false);
expect(response.body.message).toContain('exists');
// Assert only one user in database
const userCount = await userRepository.count();
expect(userCount).toBe(1);
});
});
describe('GET /api/users/:id', () => {
let testUser: User;
beforeEach(async () => {
testUser = await userRepository.save({
email: 'test@example.com',
password: 'hashedPassword123',
firstName: 'John',
lastName: 'Doe',
});
});
it('should return user by ID', async () => {
const response = await request(app)
.get(`/api/users/${testUser.id}`)
.expect(200);
expect(response.body.success).toBe(true);
expect(response.body.data).toMatchObject({
id: testUser.id,
email: testUser.email,
firstName: testUser.firstName,
lastName: testUser.lastName,
});
expect(response.body.data.password).toBeUndefined();
});
it('should return 404 for non-existent user', async () => {
const nonExistentId = '999';
const response = await request(app)
.get(`/api/users/${nonExistentId}`)
.expect(404);
expect(response.body.success).toBe(false);
expect(response.body.message).toContain('not found');
});
});
describe('PUT /api/users/:id', () => {
let testUser: User;
beforeEach(async () => {
testUser = await userRepository.save({
email: 'test@example.com',
password: 'hashedPassword123',
firstName: 'John',
lastName: 'Doe',
});
});
it('should update user successfully', async () => {
const updateData: UpdateUserDto = {
firstName: 'Jane',
lastName: 'Smith',
};
const response = await request(app)
.put(`/api/users/${testUser.id}`)
.send(updateData)
.expect(200);
expect(response.body.success).toBe(true);
expect(response.body.data.firstName).toBe(updateData.firstName);
expect(response.body.data.lastName).toBe(updateData.lastName);
// Verify database update
const updatedUser = await userRepository.findOne({
where: { id: testUser.id },
});
expect(updatedUser.firstName).toBe(updateData.firstName);
expect(updatedUser.lastName).toBe(updateData.lastName);
});
it('should hash password when updating', async () => {
const updateData: UpdateUserDto = {
password: 'newPassword123',
};
await request(app)
.put(`/api/users/${testUser.id}`)
.send(updateData)
.expect(200);
// Verify password was hashed
const updatedUser = await userRepository.findOne({
where: { id: testUser.id },
});
expect(updatedUser.password).not.toBe(updateData.password);
expect(updatedUser.password).not.toBe(testUser.password);
});
});
});
Tutorial 3: End-to-End Test Generation
Objective
Generate comprehensive E2E tests using Playwright with AI assistance.
Step 1: E2E Test Context Setup
AI Context for E2E Testing:
Generate comprehensive E2E tests using Playwright for a user management system.
## Application Under Test
- **Frontend**: React application on localhost:3000
- **Backend**: REST API on localhost:3001
- **Database**: PostgreSQL
- **Authentication**: JWT tokens with login/logout
## Test Requirements
- Test complete user journeys
- Include authentication flows
- Test form validations and error handling
- Verify data persistence across page reloads
- Test responsive design on different viewports
- Include accessibility testing
## User Flows to Test
1. User Registration → Email Verification → Login → Profile Management
2. Admin Login → User Management → Create/Edit/Delete Users
3. Password Reset Flow → Email → Set New Password → Login
4. User Search and Filtering → Export Data
Please generate comprehensive E2E tests with proper page object models and reusable utilities.
AI-Generated E2E Test Suite:
// tests/e2e/user-management.spec.ts
import { test, expect, Page } from '@playwright/test';
// Page Object Models
class LoginPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto('/login');
}
async login(email: string, password: string) {
await this.page.fill('[data-testid="email-input"]', email);
await this.page.fill('[data-testid="password-input"]', password);
await this.page.click('[data-testid="login-button"]');
}
async getErrorMessage() {
return await this.page.textContent('[data-testid="error-message"]');
}
}
class UserManagementPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto('/users');
}
async createUser(userData: {
email: string;
firstName: string;
lastName: string;
password: string;
}) {
await this.page.click('[data-testid="create-user-button"]');
await this.page.fill('[data-testid="user-email"]', userData.email);
await this.page.fill('[data-testid="user-first-name"]', userData.firstName);
await this.page.fill('[data-testid="user-last-name"]', userData.lastName);
await this.page.fill('[data-testid="user-password"]', userData.password);
await this.page.click('[data-testid="save-user-button"]');
}
async searchUsers(searchTerm: string) {
await this.page.fill('[data-testid="user-search"]', searchTerm);
await this.page.press('[data-testid="user-search"]', 'Enter');
}
async getUserCount() {
return await this.page.locator('[data-testid="user-row"]').count();
}
async deleteUser(email: string) {
await this.page.click(`[data-testid="delete-user-${email}"]`);
await this.page.click('[data-testid="confirm-delete"]');
}
}
// Test Suite
test.describe('User Management E2E Tests', () => {
let loginPage: LoginPage;
let userManagementPage: UserManagementPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
userManagementPage = new UserManagementPage(page);
// Setup test data - could be done via API calls
await page.request.post('http://localhost:3001/api/test/setup');
});
test.afterEach(async ({ page }) => {
// Cleanup test data
await page.request.post('http://localhost:3001/api/test/cleanup');
});
test('should complete full user management workflow', async ({ page }) => {
// Step 1: Admin Login
await loginPage.goto();
await loginPage.login('admin@example.com', 'admin123');
// Verify login success
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('[data-testid="user-name"]')).toContainText('Admin User');
// Step 2: Navigate to User Management
await userManagementPage.goto();
await expect(page.locator('h1')).toContainText('User Management');
// Step 3: Create New User
const newUser = {
email: 'testuser@example.com',
firstName: 'Test',
lastName: 'User',
password: 'password123',
};
const initialUserCount = await userManagementPage.getUserCount();
await userManagementPage.createUser(newUser);
// Verify user creation
await expect(page.locator('[data-testid="success-message"]'))
.toContainText('User created successfully');
const newUserCount = await userManagementPage.getUserCount();
expect(newUserCount).toBe(initialUserCount + 1);
// Step 4: Search for Created User
await userManagementPage.searchUsers(newUser.email);
await expect(page.locator('[data-testid="user-row"]')).toHaveCount(1);
await expect(page.locator('[data-testid="user-email"]'))
.toContainText(newUser.email);
// Step 5: Edit User
await page.click(`[data-testid="edit-user-${newUser.email}"]`);
await page.fill('[data-testid="user-first-name"]', 'Updated');
await page.click('[data-testid="save-user-button"]');
// Verify user update
await expect(page.locator('[data-testid="success-message"]'))
.toContainText('User updated successfully');
await expect(page.locator('[data-testid="user-name"]'))
.toContainText('Updated User');
// Step 6: Delete User
await userManagementPage.deleteUser(newUser.email);
// Verify user deletion
await expect(page.locator('[data-testid="success-message"]'))
.toContainText('User deleted successfully');
const finalUserCount = await userManagementPage.getUserCount();
expect(finalUserCount).toBe(initialUserCount);
});
test('should handle form validation errors', async ({ page }) => {
await loginPage.goto();
await loginPage.login('admin@example.com', 'admin123');
await userManagementPage.goto();
// Try to create user with invalid data
await page.click('[data-testid="create-user-button"]');
// Submit form without filling required fields
await page.click('[data-testid="save-user-button"]');
// Verify validation errors
await expect(page.locator('[data-testid="email-error"]'))
.toContainText('Email is required');
await expect(page.locator('[data-testid="firstName-error"]'))
.toContainText('First name is required');
await expect(page.locator('[data-testid="password-error"]'))
.toContainText('Password is required');
// Try with invalid email format
await page.fill('[data-testid="user-email"]', 'invalid-email');
await page.click('[data-testid="save-user-button"]');
await expect(page.locator('[data-testid="email-error"]'))
.toContainText('Please enter a valid email');
});
test('should be responsive on different screen sizes', async ({ page }) => {
await loginPage.goto();
await loginPage.login('admin@example.com', 'admin123');
await userManagementPage.goto();
// Test mobile viewport
await page.setViewportSize({ width: 375, height: 812 });
// Verify mobile navigation works
await expect(page.locator('[data-testid="mobile-menu-button"]')).toBeVisible();
await page.click('[data-testid="mobile-menu-button"]');
await expect(page.locator('[data-testid="mobile-menu"]')).toBeVisible();
// Verify table is responsive (horizontal scroll or stacked layout)
const table = page.locator('[data-testid="users-table"]');
await expect(table).toBeVisible();
// Test tablet viewport
await page.setViewportSize({ width: 768, height: 1024 });
await expect(page.locator('[data-testid="users-table"]')).toBeVisible();
// Test desktop viewport
await page.setViewportSize({ width: 1920, height: 1080 });
await expect(page.locator('[data-testid="users-table"]')).toBeVisible();
});
test('should meet accessibility requirements', async ({ page }) => {
await loginPage.goto();
// Check for proper heading hierarchy
await expect(page.locator('h1')).toBeVisible();
// Check for form labels
await expect(page.locator('label[for="email"]')).toBeVisible();
await expect(page.locator('label[for="password"]')).toBeVisible();
// Check for proper ARIA attributes
const emailInput = page.locator('[data-testid="email-input"]');
await expect(emailInput).toHaveAttribute('aria-label');
const passwordInput = page.locator('[data-testid="password-input"]');
await expect(passwordInput).toHaveAttribute('aria-label');
// Check keyboard navigation
await page.keyboard.press('Tab');
await expect(emailInput).toBeFocused();
await page.keyboard.press('Tab');
await expect(passwordInput).toBeFocused();
// Check color contrast (would need additional tools for full testing)
// This is a placeholder for actual contrast testing
const loginButton = page.locator('[data-testid="login-button"]');
await expect(loginButton).toBeVisible();
});
});
Tutorial 4: Test Data Management with AI
Objective
Generate and manage realistic test data using AI assistance.
AI-Generated Test Data Factory
// tests/factories/user.factory.ts
import { faker } from '@faker-js/faker';
import { User, CreateUserDto } from '../../src/types/user.types';
export class UserFactory {
static createUserDto(overrides: Partial<CreateUserDto> = {}): CreateUserDto {
return {
email: faker.internet.email(),
password: faker.internet.password({ length: 12 }),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
...overrides,
};
}
static createUser(overrides: Partial<User> = {}): User {
const baseUser = this.createUserDto();
return {
id: faker.string.uuid(),
...baseUser,
password: faker.string.alphanumeric(60), // Simulated hashed password
createdAt: faker.date.past(),
updatedAt: faker.date.recent(),
...overrides,
};
}
static createUsers(count: number, overrides: Partial<User> = {}): User[] {
return Array.from({ length: count }, () => this.createUser(overrides));
}
static createAdminUser(overrides: Partial<User> = {}): User {
return this.createUser({
email: 'admin@example.com',
firstName: 'Admin',
lastName: 'User',
role: 'admin',
...overrides,
});
}
static createTestScenarioUsers(): {
admin: User;
regularUsers: User[];
inactiveUsers: User[];
recentUsers: User[];
} {
return {
admin: this.createAdminUser(),
regularUsers: this.createUsers(10, { role: 'user', isActive: true }),
inactiveUsers: this.createUsers(3, { role: 'user', isActive: false }),
recentUsers: this.createUsers(5, {
role: 'user',
createdAt: faker.date.recent({ days: 7 })
}),
};
}
}
// Usage in tests
describe('User Service with AI-Generated Data', () => {
it('should handle bulk user operations', async () => {
const testData = UserFactory.createTestScenarioUsers();
// Test with realistic data scenarios
const result = await userService.bulkCreateUsers(testData.regularUsers);
expect(result.created).toHaveLength(10);
expect(result.errors).toHaveLength(0);
});
});
Tutorial 5: Visual Regression Testing with AI
Objective
Implement visual regression testing using AI-powered image comparison.
AI-Enhanced Visual Testing
// tests/visual/visual-regression.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Visual Regression Tests', () => {
test('should match user management page layout', async ({ page }) => {
// Navigate and prepare page
await page.goto('/users');
await page.waitForLoadState('networkidle');
// Hide dynamic content
await page.addStyleTag({
content: `
[data-testid="timestamp"],
[data-testid="last-login"] {
visibility: hidden !important;
}
`
});
// Take screenshot and compare
await expect(page).toHaveScreenshot('user-management-page.png');
});
test('should match user creation modal', async ({ page }) => {
await page.goto('/users');
await page.click('[data-testid="create-user-button"]');
// Wait for modal animation
await page.waitForTimeout(300);
const modal = page.locator('[data-testid="user-modal"]');
await expect(modal).toHaveScreenshot('user-creation-modal.png');
});
test('should match responsive layouts', async ({ page }) => {
await page.goto('/users');
// Test different viewport sizes
const viewports = [
{ width: 375, height: 812, name: 'mobile' },
{ width: 768, height: 1024, name: 'tablet' },
{ width: 1920, height: 1080, name: 'desktop' },
];
for (const viewport of viewports) {
await page.setViewportSize({ width: viewport.width, height: viewport.height });
await page.waitForTimeout(500); // Allow layout to adjust
await expect(page).toHaveScreenshot(`user-page-${viewport.name}.png`);
}
});
});
Advanced AI Testing Techniques
Technique 1: AI-Powered Test Case Generation
# AI Test Case Generation Prompt
Analyze the following user story and generate comprehensive test cases:
## User Story
**As a** registered user
**I want** to update my profile information
**So that** my account details remain current and accurate
**Acceptance Criteria:**
- User can update first name, last name, email, and phone number
- Email format must be valid
- Phone number must be valid format
- Changes must be saved to database
- User receives confirmation of successful update
- User cannot use email address already taken by another user
## Generate Test Cases For:
1. Happy path scenarios
2. Edge cases and boundary conditions
3. Error scenarios and validation
4. Security considerations
5. Performance edge cases
6. Accessibility requirements
Please provide test cases in Given-When-Then format with specific test data examples.
Technique 2: AI-Assisted Test Maintenance
// AI-powered test maintenance utility
class TestMaintenanceAssistant {
async analyzeFailingTests(testResults: TestResult[]): Promise<MaintenanceReport> {
const failingTests = testResults.filter(test => !test.passed);
const analysis = await this.aiAnalyzeFailures(failingTests);
return {
commonFailurePatterns: analysis.patterns,
suggestedFixes: analysis.fixes,
testUpdateRecommendations: analysis.recommendations,
potentialFlakiness: analysis.flakiness,
};
}
async suggestTestUpdates(
codeChanges: CodeChange[],
existingTests: TestSuite[]
): Promise<TestUpdateSuggestion[]> {
// AI analyzes code changes and suggests test updates
return await this.aiAnalyzeCodeChanges(codeChanges, existingTests);
}
}
Technique 3: Intelligent Test Selection
// AI-powered test selection based on code changes
class SmartTestRunner {
async selectTestsForChanges(
changedFiles: string[],
allTests: TestFile[]
): Promise<TestSelectionResult> {
const analysis = await this.aiAnalyzeImpact(changedFiles);
return {
criticalTests: analysis.mustRun,
recommendedTests: analysis.shouldRun,
optionalTests: analysis.couldRun,
skippableTests: analysis.canSkip,
estimatedRunTime: analysis.timeEstimate,
};
}
}
Best Practices for AI-Assisted Testing
Do's ✅
- Review All Generated Tests: Never use AI-generated tests without review
- Validate Test Logic: Ensure tests actually test what they claim to test
- Maintain Test Data: Keep test data realistic and up-to-date
- Focus on Business Value: Generate tests that provide meaningful coverage
- Iterate and Improve: Use AI feedback to continuously improve test quality
Don'ts ❌
- Don't Trust Blindly: Always verify AI-generated test assertions
- Don't Over-Generate: Quality over quantity - avoid test bloat
- Don't Ignore Maintenance: AI-generated tests still need maintenance
- Don't Skip Manual Review: Always review for edge cases and scenarios
- Don't Forget Context: Provide sufficient context for accurate test generation
Measuring AI-Assisted Testing Success
Key Metrics
interface TestingMetrics {
coverage: {
linesCovered: number;
branchesCovered: number;
functionsCovered: number;
statementsCovered: number;
};
quality: {
testReliability: number;
falsePositiveRate: number;
defectDetectionRate: number;
testMaintainabilityScore: number;
};
efficiency: {
testCreationTime: number;
testExecutionTime: number;
testMaintenanceTime: number;
aiAssistanceUsage: number;
};
}
Success Indicators
- 90%+ code coverage with meaningful tests
- Less than 5% false positive rate on test failures
- 50%+ reduction in test creation time
- 30%+ improvement in defect detection before production
Next Steps
- Start Small: Begin with unit test generation for a single module
- Build Confidence: Gradually expand to integration and E2E tests
- Measure Impact: Track metrics to validate AI testing effectiveness
- Share Knowledge: Train team members on AI-assisted testing techniques
- Iterate: Continuously improve prompts and processes based on results
Ready to Practice? Try our AI Testing Exercises → or continue with Code Quality Integration →.
Need Support? Join the GISE Testing Community → for tips and troubleshooting!