Testing fundamentals
Skill Primadetaautomation/primadata-marketplace/.claude/skills/testing-fundamentals
TDD workflow, comprehensive test strategies, test coverage, and quality assurance patternsFrom its SKILL.md
npx -y skills add Primadetaautomation/primadata-marketplace --skill testing-fundamentalsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
11.3 KB, as published. Nobody here has run it
Testing Fundamentals Skill
Overview
This skill provides comprehensive testing strategies following TDD principles with 80%+ coverage requirements. It ensures quality assurance through systematic testing approaches.
When to Use This Skill
- Implementing new features (TDD approach)
- Creating comprehensive test suites
- Analyzing test coverage gaps
- Pre-production quality validation
- Refactoring with safety net
TDD Workflow (Level 1 - Always Loaded)
π΄ Red β π’ Green β π΅ Refactor
Step 1: Red - Write Failing Test First
// Write the test BEFORE implementation
describe('UserService', () => {
it('should create a new user with valid data', async () => {
// Arrange
const userData = {
email: '[email protected]',
password: 'SecurePass123!',
name: 'Test User'
};
// Act
const result = await userService.createUser(userData);
// Assert
expect(result).toHaveProperty('id');
expect(result.email).toBe(userData.email);
expect(result.name).toBe(userData.name);
expect(result).not.toHaveProperty('password'); // Password should not be returned
});
});
// Test should FAIL initially (Red)
Step 2: Green - Write Minimal Code to Pass
class UserService {
async createUser(data: CreateUserDto): Promise<User> {
// Minimal implementation to make test pass
const user = {
id: generateId(),
email: data.email,
name: data.name,
// password is hashed and not returned
};
await this.userRepository.save(user);
return user;
}
}
// Test should PASS now (Green)
Step 3: Refactor - Improve Code Quality
class UserService {
async createUser(data: CreateUserDto): Promise<User> {
// Refactor with better structure
this.validateUserData(data);
const hashedPassword = await this.hashPassword(data.password);
const user = User.create({
email: data.email,
name: data.name,
passwordHash: hashedPassword,
});
return this.userRepository.save(user);
}
private validateUserData(data: CreateUserDto): void {
if (!validator.isEmail(data.email)) {
throw new ValidationError('Invalid email');
}
if (data.password.length < 8) {
throw new ValidationError('Password too short');
}
}
private async hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, 12);
}
}
// Tests still PASS after refactoring
Test Coverage Requirements
Minimum Standards:
- 80%+ overall coverage (lines, branches, functions)
- 100% coverage for critical business logic
- All error paths tested
- Edge cases covered
What to Test:
- β Happy path (normal flow)
- β Error scenarios (validation failures, exceptions)
- β Edge cases (empty arrays, null values, boundary conditions)
- β Integration points (API calls, database operations)
- β Security (unauthorized access, input validation)
Arrange-Act-Assert (AAA) Pattern
describe('OrderService', () => {
it('should calculate total with tax correctly', () => {
// ===== ARRANGE =====
// Set up test data and dependencies
const mockTaxService = {
getTaxRate: jest.fn().mockResolvedValue(0.21)
};
const orderService = new OrderService(mockTaxService);
const items = [
{ price: 100, quantity: 2 },
{ price: 50, quantity: 1 }
];
// ===== ACT =====
// Execute the function being tested
const result = await orderService.calculateTotal(items);
// ===== ASSERT =====
// Verify the results
expect(result.subtotal).toBe(250);
expect(result.tax).toBe(52.5);
expect(result.total).toBe(302.5);
expect(mockTaxService.getTaxRate).toHaveBeenCalledTimes(1);
});
});
Test Types & When to Use
1. Unit Tests (Fast, Isolated)
// Test single function/method in isolation
describe('calculateDiscount', () => {
it('should apply 10% discount for orders over $100', () => {
expect(calculateDiscount(150)).toBe(15);
});
it('should return 0 for orders under $100', () => {
expect(calculateDiscount(50)).toBe(0);
});
});
When to use:
- Testing pure functions
- Business logic validation
- Utility functions
- Unit-level validation
2. Integration Tests (Realistic)
// Test multiple components together
describe('User Registration Integration', () => {
it('should register user and send welcome email', async () => {
// Uses real UserService, UserRepository, and EmailService
const result = await userService.register({
email: '[email protected]',
password: 'Test123!'
});
expect(result.user).toBeDefined();
// Verify email was sent
const emails = await testEmailService.getSentEmails();
expect(emails).toHaveLength(1);
expect(emails[0].to).toBe('[email protected]');
});
});
When to use:
- API endpoint testing
- Database operations
- Service layer integration
- External service integration
3. E2E Tests (Full User Journey)
// Test complete user flows (Playwright/Cypress)
test('user can complete checkout process', async ({ page }) => {
// Navigate to site
await page.goto('https://example.com');
// Add items to cart
await page.click('[data-testid="add-to-cart"]');
// Go to checkout
await page.click('[data-testid="checkout-button"]');
// Fill shipping info
await page.fill('[name="address"]', '123 Test St');
await page.fill('[name="city"]', 'Amsterdam');
// Complete payment
await page.click('[data-testid="pay-now"]');
// Verify success
await expect(page.locator('.success-message')).toBeVisible();
});
When to use:
- Critical user journeys
- Cross-browser testing
- Visual regression
- Accessibility validation
Test Data Management
Factory Pattern
// Test data factory for consistent test data
class UserFactory {
static create(overrides: Partial<User> = {}): User {
return {
id: faker.string.uuid(),
email: faker.internet.email(),
name: faker.person.fullName(),
createdAt: new Date(),
...overrides
};
}
static createMany(count: number): User[] {
return Array.from({ length: count }, () => this.create());
}
static createAdmin(): User {
return this.create({
role: 'admin',
permissions: ['read', 'write', 'delete']
});
}
}
// Usage in tests
describe('UserService', () => {
it('should handle multiple users', () => {
const users = UserFactory.createMany(5);
expect(users).toHaveLength(5);
});
it('should allow admin to delete users', () => {
const admin = UserFactory.createAdmin();
expect(admin.permissions).toContain('delete');
});
});
Mocking Best Practices
Mock External Dependencies
describe('PaymentService', () => {
let paymentService: PaymentService;
let mockStripeClient: jest.Mocked<StripeClient>;
let mockDatabase: jest.Mocked<Database>;
beforeEach(() => {
// Create mocks
mockStripeClient = {
createCharge: jest.fn(),
refund: jest.fn(),
} as any;
mockDatabase = {
saveTransaction: jest.fn(),
} as any;
// Inject mocks
paymentService = new PaymentService(mockStripeClient, mockDatabase);
});
it('should process payment and save transaction', async () => {
// Arrange
mockStripeClient.createCharge.mockResolvedValue({ id: 'ch_123', status: 'succeeded' });
mockDatabase.saveTransaction.mockResolvedValue(true);
// Act
await paymentService.processPayment(100, 'usd');
// Assert
expect(mockStripeClient.createCharge).toHaveBeenCalledWith({
amount: 100,
currency: 'usd'
});
expect(mockDatabase.saveTransaction).toHaveBeenCalled();
});
});
Test Organization
Describe Blocks for Structure
describe('UserService', () => {
describe('createUser', () => {
it('should create user with valid data', () => { /* ... */ });
it('should throw error with invalid email', () => { /* ... */ });
it('should throw error with weak password', () => { /* ... */ });
});
describe('updateUser', () => {
it('should update user fields', () => { /* ... */ });
it('should not update immutable fields', () => { /* ... */ });
});
describe('deleteUser', () => {
it('should soft delete user', () => { /* ... */ });
it('should throw error if user not found', () => { /* ... */ });
});
});
Testing Checklist
Before marking feature complete:
- Tests written BEFORE implementation (TDD)
- Happy path tested
- Error scenarios tested
- Edge cases covered
- 80%+ coverage achieved
- No flaky tests
- Tests run fast (< 5s for unit tests)
- Descriptive test names
- AAA pattern used
- Mocks properly isolated
- Integration tests for critical paths
- E2E tests for user journeys
Common Testing Mistakes
β BAD: Testing Implementation Details
it('should call getUserById method', () => {
const spy = jest.spyOn(userService, 'getUserById');
userService.getUser('123');
expect(spy).toHaveBeenCalled(); // Testing HOW, not WHAT
});
β GOOD: Testing Behavior
it('should return user data when valid ID provided', () => {
const user = userService.getUser('123');
expect(user).toBeDefined();
expect(user.id).toBe('123'); // Testing WHAT happens
});
β BAD: Multiple Assertions Testing Different Things
it('should work correctly', () => {
expect(userService.create(data)).toBeDefined();
expect(userService.delete('123')).toBe(true);
expect(userService.list()).toHaveLength(5);
// Too many unrelated assertions
});
β GOOD: One Behavior Per Test
it('should create user successfully', () => {
expect(userService.create(data)).toBeDefined();
});
it('should delete user when valid ID provided', () => {
expect(userService.delete('123')).toBe(true);
});
it('should list all users', () => {
expect(userService.list()).toHaveLength(5);
});
Detailed Testing Strategies (Level 2 - Load on Request)
See companion files:
advanced-mocking.md- Complex mocking scenariosperformance-testing.md- Load and stress testingsnapshot-testing.md- Visual and data snapshot strategies
Test Templates (Level 3 - Load When Needed)
See templates directory:
templates/unit-test.template.tstemplates/integration-test.template.tstemplates/e2e-test.template.ts
Integration with Agents
qa-testing-engineer:
- Primary agent for test strategy and implementation
- Uses this skill for all testing tasks
- Ensures coverage requirements met
senior-fullstack-developer:
- Uses this skill for TDD workflow
- References patterns during feature development
playwright-test-agent:
- Uses E2E testing sections
- Focuses on browser automation patterns
Version 1.0.0 | TDD Compliant | 80%+ Coverage Required