test-expert

Testing methodologies, test-driven development (TDD), unit and integration testing, and testing best practices across multiple frameworks. Use when the user needs to write tests, implement TDD, or improve test coverage and quality.

118 stars

Best use case

test-expert is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Testing methodologies, test-driven development (TDD), unit and integration testing, and testing best practices across multiple frameworks. Use when the user needs to write tests, implement TDD, or improve test coverage and quality.

Teams using test-expert 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/test-expert/SKILL.md --create-dirs "https://raw.githubusercontent.com/einverne/dotfiles/main/claude/skills/test-expert/SKILL.md"

Manual Installation

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

How test-expert Compares

Feature / Agenttest-expertStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Testing methodologies, test-driven development (TDD), unit and integration testing, and testing best practices across multiple frameworks. Use when the user needs to write tests, implement TDD, or improve test coverage and quality.

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.

Related Guides

SKILL.md Source

You are a testing expert. Your role is to help users write effective tests, follow TDD practices, and ensure code quality through comprehensive test coverage.

## Testing Principles

### 1. Test Pyramid
```
        /\
       /  \  E2E Tests (Few)
      /____\
     /      \  Integration Tests (Some)
    /________\
   /          \  Unit Tests (Many)
  /__________\
```

- **Unit Tests**: Fast, isolated, test single components
- **Integration Tests**: Test component interactions
- **E2E Tests**: Test entire user flows

### 2. FIRST Principles
- **F**ast: Tests should run quickly
- **I**solated: Tests shouldn't depend on each other
- **R**epeatable: Same result every time
- **S**elf-Validating: Pass or fail, no manual checking
- **T**imely: Write tests before or with code

### 3. Test Coverage Goals
- Aim for 80%+ coverage
- 100% coverage for critical paths
- Focus on important business logic
- Don't test framework code
- Don't obsess over 100%

## Test-Driven Development (TDD)

### Red-Green-Refactor Cycle

1. **Red**: Write a failing test
```python
def test_add_numbers():
    assert add(2, 3) == 5  # Function doesn't exist yet
```

2. **Green**: Write minimal code to pass
```python
def add(a, b):
    return a + b
```

3. **Refactor**: Improve code quality
```python
def add(a: int, b: int) -> int:
    """Add two numbers and return the result."""
    return a + b
```

### TDD Benefits
- Forces you to think about API design
- Ensures testable code
- Provides immediate feedback
- Creates living documentation
- Prevents over-engineering

## Unit Testing

### Good Unit Test Characteristics

```python
# Good: Clear, focused, independent
def test_user_can_be_created_with_email():
    # Arrange
    email = "user@example.com"

    # Act
    user = User(email=email)

    # Assert
    assert user.email == email
    assert user.is_active == True
```

### AAA Pattern
- **Arrange**: Set up test data
- **Act**: Execute the code under test
- **Assert**: Verify the result

### Test Naming
```python
# Good names describe what's being tested
def test_user_creation_with_valid_email_succeeds():
    pass

def test_user_creation_with_invalid_email_raises_error():
    pass

def test_empty_cart_has_zero_total():
    pass
```

## Testing by Language

### Python (pytest)
```python
import pytest
from myapp import Calculator

class TestCalculator:
    @pytest.fixture
    def calc(self):
        return Calculator()

    def test_add(self, calc):
        assert calc.add(2, 3) == 5

    def test_divide_by_zero_raises_error(self, calc):
        with pytest.raises(ZeroDivisionError):
            calc.divide(10, 0)

    @pytest.mark.parametrize("a,b,expected", [
        (2, 3, 5),
        (0, 0, 0),
        (-1, 1, 0),
    ])
    def test_add_multiple_cases(self, calc, a, b, expected):
        assert calc.add(a, b) == expected
```

### JavaScript (Jest)
```javascript
describe('Calculator', () => {
  let calc;

  beforeEach(() => {
    calc = new Calculator();
  });

  test('adds two numbers', () => {
    expect(calc.add(2, 3)).toBe(5);
  });

  test('throws error on division by zero', () => {
    expect(() => calc.divide(10, 0)).toThrow();
  });

  test.each([
    [2, 3, 5],
    [0, 0, 0],
    [-1, 1, 0],
  ])('add(%i, %i) returns %i', (a, b, expected) => {
    expect(calc.add(a, b)).toBe(expected);
  });
});
```

### Shell Scripts (bats)
```bash
#!/usr/bin/env bats

@test "script exits with status 0 on success" {
  run ./myscript.sh input.txt
  [ "$status" -eq 0 ]
}

@test "script produces expected output" {
  run ./myscript.sh input.txt
  [ "${lines[0]}" = "Expected output" ]
}

@test "script fails with invalid input" {
  run ./myscript.sh nonexistent.txt
  [ "$status" -ne 0 ]
  [[ "$output" =~ "Error" ]]
}
```

## Mocking and Stubbing

### When to Mock
- External services (APIs, databases)
- Slow operations
- Non-deterministic behavior (random, time)
- Hard-to-trigger scenarios (errors)

### Python Mocking
```python
from unittest.mock import Mock, patch, MagicMock

# Mock an object
mock_db = Mock()
mock_db.get_user.return_value = {"id": 1, "name": "Test"}

# Patch a function
@patch('myapp.external_api_call')
def test_function(mock_api):
    mock_api.return_value = {"status": "success"}
    result = my_function()
    assert result == expected
    mock_api.assert_called_once_with(expected_arg)
```

### JavaScript Mocking
```javascript
// Jest mocking
jest.mock('./api');
import { fetchUser } from './api';

test('loads user data', async () => {
  fetchUser.mockResolvedValue({ id: 1, name: 'Test' });

  const user = await loadUser(1);

  expect(user.name).toBe('Test');
  expect(fetchUser).toHaveBeenCalledWith(1);
});
```

## Integration Testing

### Database Testing
```python
import pytest
from myapp import create_app, db

@pytest.fixture
def app():
    app = create_app('testing')
    with app.app_context():
        db.create_all()
        yield app
        db.session.remove()
        db.drop_all()

def test_user_can_be_saved_to_database(app):
    user = User(email='test@example.com')
    db.session.add(user)
    db.session.commit()

    retrieved = User.query.filter_by(email='test@example.com').first()
    assert retrieved is not None
    assert retrieved.email == 'test@example.com'
```

### API Testing
```python
def test_api_returns_user_list(client):
    response = client.get('/api/users')

    assert response.status_code == 200
    assert len(response.json) > 0
    assert 'email' in response.json[0]
```

## End-to-End Testing

### Web Testing (Playwright/Selenium)
```javascript
// Playwright example
test('user can login', async ({ page }) => {
  await page.goto('https://example.com');

  await page.fill('[name="email"]', 'user@example.com');
  await page.fill('[name="password"]', 'password123');
  await page.click('button[type="submit"]');

  await expect(page.locator('.welcome')).toContainText('Welcome back');
});
```

## Test Fixtures and Factories

### Fixtures
```python
@pytest.fixture
def sample_user():
    return User(
        email='test@example.com',
        name='Test User'
    )

@pytest.fixture
def authenticated_client(client, sample_user):
    client.login(sample_user)
    return client
```

### Factories
```python
import factory

class UserFactory(factory.Factory):
    class Meta:
        model = User

    email = factory.Sequence(lambda n: f'user{n}@example.com')
    name = factory.Faker('name')
    is_active = True

# Usage
user = UserFactory()
admin = UserFactory(is_admin=True)
users = UserFactory.create_batch(10)
```

## Testing Best Practices

### Do's
- ✅ Write tests first (TDD)
- ✅ Test behavior, not implementation
- ✅ Keep tests simple and readable
- ✅ Use descriptive test names
- ✅ Test edge cases and errors
- ✅ Keep tests fast
- ✅ Make tests independent
- ✅ Use fixtures for common setup

### Don'ts
- ❌ Test framework/library code
- ❌ Test multiple things in one test
- ❌ Use random data without seeding
- ❌ Depend on test execution order
- ❌ Leave commented-out tests
- ❌ Skip tests without good reason
- ❌ Have flaky tests

## Test Organization

```
project/
├── src/
│   └── myapp/
│       ├── __init__.py
│       └── calculator.py
└── tests/
    ├── __init__.py
    ├── conftest.py          # Shared fixtures
    ├── unit/
    │   └── test_calculator.py
    ├── integration/
    │   └── test_database.py
    └── e2e/
        └── test_user_flow.py
```

## Code Coverage

### Generate Coverage Report
```bash
# Python
pytest --cov=myapp --cov-report=html

# JavaScript
jest --coverage

# View coverage
open htmlcov/index.html
```

### Coverage Goals
- Critical business logic: 100%
- Most code: 80%+
- E2E scripts: Lower coverage OK
- Don't sacrifice test quality for coverage numbers

## Common Testing Patterns

### Testing Exceptions
```python
def test_raises_error():
    with pytest.raises(ValueError, match="Invalid input"):
        function_that_raises("bad")
```

### Testing Async Code
```python
@pytest.mark.asyncio
async def test_async_function():
    result = await async_function()
    assert result == expected
```

### Testing Time-Dependent Code
```python
@patch('myapp.datetime')
def test_time_dependent(mock_datetime):
    mock_datetime.now.return_value = datetime(2024, 1, 1)
    result = function_using_time()
    assert result == expected
```

## Continuous Integration

```yaml
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run tests
        run: |
          pip install -r requirements-dev.txt
          pytest --cov --cov-report=xml
      - name: Upload coverage
        uses: codecov/codecov-action@v2
```

Remember: Good tests are your safety net. They give you confidence to refactor and add features. Invest time in writing quality tests!

Related Skills

Claude Code Expert Skill

118
from einverne/dotfiles

This skill provides comprehensive guidance on using Claude Code, Anthropic's agentic coding tool.

git-commit-formatter

118
from einverne/dotfiles

生成符合 Conventional Commits 规范的 Git 提交信息。当用户要求生成提交、创建 commit 或写提交信息时使用

deploy-staging

118
from einverne/dotfiles

将当前分支部署到测试环境。当用户要求部署、发布到测试或在 staging 环境测试时使用

code-reviewer

118
from einverne/dotfiles

进行系统化的代码审查,检查代码质量、安全性和性能。当用户要求审查代码、review 或检查代码时使用

turborepo

118
from einverne/dotfiles

Guide for implementing Turborepo - a high-performance build system for JavaScript and TypeScript monorepos. Use when setting up monorepos, optimizing build performance, implementing task pipelines, configuring caching strategies, or orchestrating tasks across multiple packages.

template-skill

118
from einverne/dotfiles

Replace with description of the skill and when Claude should use it.

tailwindcss

118
from einverne/dotfiles

Guide for implementing Tailwind CSS - a utility-first CSS framework for rapid UI development. Use when styling applications with responsive design, dark mode, custom themes, or building design systems with Tailwind's utility classes.

skill-creator

118
from einverne/dotfiles

Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.

shopify

118
from einverne/dotfiles

Guide for implementing Shopify apps, extensions, themes, and integrations using GraphQL/REST APIs, Shopify CLI, Polaris UI, and various extension types (Checkout, Admin, POS). Use when building Shopify apps, implementing checkout extensions, customizing admin interfaces, creating themes with Liquid, or integrating with Shopify's APIs.

shell-scripting

118
from einverne/dotfiles

Specialized knowledge of Bash and Zsh scripting, shell automation, command-line tools, and scripting best practices. Use when the user needs to write, debug, or optimize shell scripts or work with command-line tools.

shadcn-ui

118
from einverne/dotfiles

Guide for implementing shadcn/ui - a collection of beautifully-designed, accessible UI components built with Radix UI and Tailwind CSS. Use when building user interfaces, adding UI components, or implementing design systems in React-based applications.

repomix

118
from einverne/dotfiles

Guide for using Repomix - a powerful tool that packs entire repositories into single, AI-friendly files. Use when packaging codebases for AI analysis, generating context for LLMs, creating codebase snapshots, analyzing third-party libraries, or preparing repositories for security audits.