testing-strategies

Testing strategies, patterns, and best practices for production code

16 stars

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

$curl -o ~/.claude/skills/testing-strategies/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/testing-security/testing-strategies/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/testing-strategies/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How testing-strategies Compares

Feature / Agenttesting-strategiesStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/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 testing

Related Skills

web-security-testing

16
from diegosouzapw/awesome-omni-skill

Web application security testing workflow for OWASP Top 10 vulnerabilities including injection, XSS, authentication flaws, and access control issues.

web-app-testing

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

Generate comprehensive, maintainable unit tests across languages with strong coverage and edge case focus.

treido-testing

16
from diegosouzapw/awesome-omni-skill

Testing specialist for Treido (Playwright + Next.js). Use for writing/debugging E2E tests, deflaking, selectors, auth state, parallel execution, and CI stability.

testing-workflow

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

Comprehensive guide for implementing AIDB tests following E2E-first philosophy, DebugInterface abstraction, and MCP response health standards

testing-services

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

Testing patterns using bun:test with in-memory SQLite. Use when writing unit tests, integration tests, or router tests.

testing-obsessive

16
from diegosouzapw/awesome-omni-skill

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

16
from diegosouzapw/awesome-omni-skill

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.