testing-strategies
Testing strategies, patterns, and best practices for production code
Best use case
testing-strategies is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Testing strategies, patterns, and best practices for production code
Teams using testing-strategies should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/testing-strategies/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How testing-strategies Compares
| Feature / Agent | testing-strategies | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Testing strategies, patterns, and best practices for production code
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Testing Strategies Skill
## Overview
This skill provides comprehensive guidelines for implementing effective testing strategies across unit, integration, and end-to-end testing.
## Testing Pyramid
```
/\
/ \ E2E Tests (10%)
/____\ Slow, expensive, critical paths
/ \
/________\ Integration Tests (30%)
/ \ Component interactions, APIs
/____________\
/ \
Unit Tests (60%) Fast, cheap, comprehensive
```
## Unit Testing
### 1. Principles
```go
// FIRST Principles:
// F - Fast (milliseconds)
// I - Isolated (no dependencies)
// R - Repeatable (same result every time)
// S - Self-verifying (no manual checking)
// T - Timely (write with code)
// AAA Pattern:
// Arrange - Set up test data and mocks
// Act - Execute the code under test
// Assert - Verify the results
func TestUserService_CreateUser(t *testing.T) {
// Arrange
mockRepo := &mockUserRepository{}
mockRepo.On("Create", mock.Anything, mock.Anything).Return(nil)
service := NewUserService(mockRepo)
ctx := context.Background()
req := CreateUserRequest{
Email: "user@example.com",
Name: "John Doe",
}
// Act
user, err := service.CreateUser(ctx, req)
// Assert
assert.NoError(t, err)
assert.NotNil(t, user)
assert.Equal(t, "user@example.com", user.Email)
mockRepo.AssertExpectations(t)
}
```
### 2. Table-Driven Tests
```go
func TestCalculateDiscount(t *testing.T) {
tests := []struct {
name string
price float64
discountCode string
expectedPrice float64
expectedError bool
}{
{
name: "valid 10% discount",
price: 100.0,
discountCode: "SAVE10",
expectedPrice: 90.0,
expectedError: false,
},
{
name: "valid 20% discount",
price: 100.0,
discountCode: "SAVE20",
expectedPrice: 80.0,
expectedError: false,
},
{
name: "invalid discount code",
price: 100.0,
discountCode: "INVALID",
expectedPrice: 0.0,
expectedError: true,
},
{
name: "negative price",
price: -50.0,
discountCode: "SAVE10",
expectedPrice: 0.0,
expectedError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := CalculateDiscount(tt.price, tt.discountCode)
if tt.expectedError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.InDelta(t, tt.expectedPrice, result, 0.01)
}
})
}
}
```
### 3. Mocking
```go
// Interface for dependency injection
type EmailService interface {
Send(ctx context.Context, to string, subject string, body string) error
}
// Mock implementation
type mockEmailService struct {
mock.Mock
}
func (m *mockEmailService) Send(ctx context.Context, to string, subject string, body string) error {
args := m.Called(ctx, to, subject, body)
return args.Error(0)
}
// Test with mock
func TestNotificationService_NotifyUser(t *testing.T) {
mockEmail := &mockEmailService{}
mockEmail.On("Send",
mock.Anything,
"user@example.com",
"Welcome!",
mock.Anything,
).Return(nil)
service := NewNotificationService(mockEmail)
err := service.NotifyUser(context.Background(), "user@example.com", "Welcome!")
assert.NoError(t, err)
mockEmail.AssertCalled(t, "Send",
mock.Anything,
"user@example.com",
"Welcome!",
mock.Anything,
)
}
```
## Integration Testing
### 1. Database Integration
```go
func TestUserRepository_Create(t *testing.T) {
// Setup test database
ctx := context.Background()
db := setupTestDB(t)
defer teardownTestDB(t, db)
repo := NewUserRepository(db)
// Test
user := &User{
Email: "test@example.com",
Name: "Test User",
}
err := repo.Create(ctx, user)
require.NoError(t, err)
assert.NotEmpty(t, user.ID)
// Verify in database
var count int
err = db.QueryRowContext(ctx, "SELECT COUNT(*) FROM users WHERE email = $1", user.Email).Scan(&count)
require.NoError(t, err)
assert.Equal(t, 1, count)
}
// Test database setup
type testDB struct {
*sql.DB
name string
}
func setupTestDB(t *testing.T) *testDB {
// Create isolated test database
dbName := fmt.Sprintf("test_%s_%d", t.Name(), time.Now().Unix())
connStr := fmt.Sprintf("host=localhost user=postgres password=secret dbname=%s sslmode=disable", dbName)
db, err := sql.Open("postgres", connStr)
require.NoError(t, err)
// Run migrations
runMigrations(db)
return &testDB{DB: db, name: dbName}
}
func teardownTestDB(t *testing.T, db *testDB) {
db.Close()
// Drop test database
}
```
### 2. HTTP API Testing
```typescript
// API integration test
import request from 'supertest';
import { app } from '../src/app';
import { setupTestDB, teardownTestDB } from './helpers/database';
describe('POST /api/users', () => {
beforeAll(async () => {
await setupTestDB();
});
afterAll(async () => {
await teardownTestDB();
});
it('should create a new user', async () => {
const response = await request(app)
.post('/api/users')
.send({
email: 'test@example.com',
name: 'Test User'
})
.expect(201);
expect(response.body).toMatchObject({
email: 'test@example.com',
name: 'Test User'
});
expect(response.body.id).toBeDefined();
});
it('should return 400 for invalid email', async () => {
const response = await request(app)
.post('/api/users')
.send({
email: 'invalid-email',
name: 'Test User'
})
.expect(400);
expect(response.body.error).toBeDefined();
});
it('should return 409 for duplicate email', async () => {
// Create user first
await request(app)
.post('/api/users')
.send({
email: 'duplicate@example.com',
name: 'Test User'
});
// Try to create again
await request(app)
.post('/api/users')
.send({
email: 'duplicate@example.com',
name: 'Test User'
})
.expect(409);
});
});
```
### 3. External Service Testing
```go
// Use test containers for external services
func TestWithRedis(t *testing.T) {
ctx := context.Background()
// Start Redis container
req := testcontainers.ContainerRequest{
Image: "redis:latest",
ExposedPorts: []string{"6379/tcp"},
WaitingFor: wait.ForListeningPort("6379/tcp"),
}
redisC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
require.NoError(t, err)
defer redisC.Terminate(ctx)
// Connect to Redis
endpoint, err := redisC.Endpoint(ctx, "")
require.NoError(t, err)
client := redis.NewClient(&redis.Options{
Addr: endpoint,
})
// Test cache operations
cache := NewCache(client)
err = cache.Set(ctx, "key", "value", time.Hour)
require.NoError(t, err)
val, err := cache.Get(ctx, "key")
require.NoError(t, err)
assert.Equal(t, "value", val)
}
```
## End-to-End Testing
### 1. E2E with Playwright
```typescript
// e2e/user-journey.spec.ts
import { test, expect } from '@playwright/test';
test.describe('User Registration Flow', () => {
test.beforeEach(async ({ page }) => {
// Setup: Clean database, seed data if needed
await page.goto('/register');
});
test('user can register successfully', async ({ page }) => {
// Fill registration form
await page.fill('[name="email"]', 'newuser@example.com');
await page.fill('[name="password"]', 'SecurePass123!');
await page.fill('[name="confirmPassword"]', 'SecurePass123!');
// Submit form
await page.click('button[type="submit"]');
// Verify redirect to dashboard
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('h1')).toContainText('Welcome');
// Verify user is logged in
await expect(page.locator('[data-testid="user-menu"]')).toBeVisible();
});
test('shows error for existing email', async ({ page }) => {
await page.fill('[name="email"]', 'existing@example.com');
await page.fill('[name="password"]', 'SecurePass123!');
await page.click('button[type="submit"]');
await expect(page.locator('[data-testid="error-message"]'))
.toContainText('Email already exists');
});
test('validates password requirements', async ({ page }) => {
await page.fill('[name="email"]', 'test@example.com');
await page.fill('[name="password"]', 'weak');
await page.click('button[type="submit"]');
await expect(page.locator('[data-testid="password-error"]'))
.toContainText('Password must be at least 8 characters');
});
});
```
### 2. Critical Path Testing
```typescript
// Test only critical user journeys
const criticalPaths = [
{
name: 'Checkout Flow',
steps: [
'Add item to cart',
'Proceed to checkout',
'Fill shipping info',
'Enter payment',
'Confirm order'
]
},
{
name: 'User Authentication',
steps: [
'Register new account',
'Login',
'Access protected resource',
'Logout'
]
}
];
// Run these in CI pipeline
```
## Test Organization
### 1. File Structure
```
project/
├── src/
│ └── user/
│ ├── service.go
│ ├── service_test.go # Unit tests
│ └── service_integration_test.go # Integration tests (build tag)
├── tests/
│ ├── integration/
│ │ ├── api/
│ │ │ └── user_api_test.go
│ │ └── database/
│ │ └── user_repo_test.go
│ └── e2e/
│ └── user-journey.spec.ts
└── testdata/
└── fixtures/
└── users.json
```
### 2. Test Tags
```go
// Unit tests (default)
// go test ./...
// Integration tests with build tag
//go:build integration
// +build integration
package user_test
func TestUserRepositoryIntegration(t *testing.T) {
// Requires database
}
// Run: go test -tags=integration ./...
// E2E tests
//go:build e2e
// +build e2e
func TestUserJourney(t *testing.T) {
// Full system test
}
// Run: go test -tags=e2e ./...
```
## Coverage and Metrics
### 1. Coverage Targets
```bash
# Overall coverage > 80%
go test -cover ./...
# Critical code coverage > 90%
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Coverage by package
go test -coverprofile=coverage.out ./...
grep -v "_test.go" coverage.out | awk -F: '{print $1}' | sort | uniq -c | sort -rn
```
### 2. Mutation Testing
```bash
# Go
# Install: go install github.com/zimmski/go-mutesting@latest
go-mutesting ./...
# JavaScript
# Install: npm install -g stryker-cli
stryker run
```
## Best Practices
### DO:
- ✅ Test behavior, not implementation
- ✅ Use table-driven tests for multiple cases
- ✅ Keep tests independent and isolated
- ✅ Use meaningful test names
- ✅ Test edge cases and error conditions
- ✅ Use test fixtures and factories
- ✅ Mock external dependencies
- ✅ Run tests in CI/CD pipeline
### DON'T:
- ❌ Test private methods (test public API)
- ❌ Share state between tests
- ❌ Use sleep() in tests (use async/await)
- ❌ Ignore flaky tests (fix them)
- ❌ Test everything (focus on critical paths)
- ❌ Write tests that depend on order
- ❌ Use production data in tests
## When to Use
Use this skill when:
- Writing unit tests
- Setting up integration tests
- Planning test strategy
- Reviewing test coverage
- Debugging test failures
- Setting up CI/CD testingRelated Skills
web-security-testing
Web application security testing workflow for OWASP Top 10 vulnerabilities including injection, XSS, authentication flaws, and access control issues.
web-app-testing
Gemini 2.5 Computer Use for browser automation with VISIBLE local browser. Watch Gemini AI control your browser in real-time. Perfect for web app testing, automation demos, and debugging.
wallaby-testing
Check test status and debug failing tests using Wallaby.js real-time test results. Use after making code changes to verify tests pass, when checking if tests are failing, debugging test errors, analyzing assertions, inspecting runtime values, checking coverage, updating snapshots, or when user mentions Wallaby, tests, coverage, or test status.
unit-testing-test-generate
Generate comprehensive, maintainable unit tests across languages with strong coverage and edge case focus.
treido-testing
Testing specialist for Treido (Playwright + Next.js). Use for writing/debugging E2E tests, deflaking, selectors, auth state, parallel execution, and CI stability.
testing-workflow
Meta-skill that orchestrates comprehensive testing across a project by coordinating testing-patterns, e2e-testing, and testing agents. Use when setting up testing for a new project, improving coverage for an existing project, establishing a testing strategy, or verifying quality before a release.
testing-strategy
Comprehensive guide for implementing AIDB tests following E2E-first philosophy, DebugInterface abstraction, and MCP response health standards
testing-services
Writes unit tests for Python service classes using Arrange-Act-Assert pattern with proper mocking at boundaries. Tests behavior, not implementation. Mocks external systems only (API calls, file I/O, databases). Use when writing tests for services or fixing test coverage.
testing-quality
Plans and executes comprehensive testing strategy across frontend, backend, and AI tiers. Activates when writing tests, testing features, setting up test infrastructure, checking coverage, running E2E tests, or performance testing. Does not handle writing production code (backend-developer or frontend-developer), vulnerability/security review (security), or infrastructure deployment (devops).
testing-patterns
Testing patterns using bun:test with in-memory SQLite. Use when writing unit tests, integration tests, or router tests.
testing-obsessive
This skill should be used when the user mentions "write tests", "test coverage", "testing strategy", "unit tests", "integration tests", "e2e tests", "vitest", "jest", discusses testing approaches, asks about test patterns, or works on test files. Addresses testing fundamentals with emphasis on Vitest and Svelte component testing using pragmatic, risk-based approaches.
testing
Comprehensive testing specialization covering test strategy, automation, TDD methodology, test writing, and web app testing. Use when setting up test infrastructure, writing tests, implementing TDD workflows, analyzing coverage, integrating tests into CI/CD, or testing web applications with Playwright. Framework-agnostic approach with framework-specific guidance via reference files.