agentleFS
CloudAI-XCloudAI-X/opencode-workflow/skills/designing-tests/SKILL.md

designing-tests

Skill275 starsChanged 10 months agoMITView on GitHub

Guides test strategy, TDD/BDD approaches, test coverage planning, and testing best practices. Use when designing test suites, improving coverage, or choosing testing approaches.

2 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 2

    1. CloudAI-X/claude-workflow★ 1.4ksame name
    2. CloudAI-X/claude-workflow-v2★ 1.4ksame name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository6 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Write the test first: - Don't write production code without a failing test

    line 70
  2. Distinctive:

    Run tests frequently: - After every small change

    line 74
  3. Distinctive:

    Wait for conditions: - Not arbitrary sleeps

    line 324

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Designing Tests

Strategies and patterns for designing effective, maintainable test suites.

When to Use This Skill

  • Planning test coverage for new features
  • Choosing between testing approaches (TDD, BDD)
  • Designing integration or E2E tests
  • Improving existing test suites
  • Setting up testing infrastructure
  • Debugging flaky tests

The Testing Pyramid

                 ┌─────────┐
                 │   E2E   │  ← Few, slow, expensive
                 │  Tests  │     (Selenium, Playwright)
                 ├─────────┤
                 │         │
              ┌──┤ Integr- │  ← Some, medium speed
              │  │  ation  │     (API tests, DB tests)
              │  │  Tests  │
              │  ├─────────┤
              │  │         │
              │  │  Unit   │  ← Many, fast, cheap
              │  │  Tests  │     (Pure functions, isolated)
              └──┴─────────┘
LevelSpeedScopeQuantityPurpose
Unit~msSingle function/classMany (70-80%)Logic correctness
Integration~sMultiple componentsSome (15-20%)Component interaction
E2E~10s+Full systemFew (5-10%)User flows work

Test-Driven Development (TDD)

The Red-Green-Refactor Cycle

     ┌─────────────────────────────────┐
     │                                 │
     ▼                                 │
┌─────────┐    ┌─────────┐    ┌────────┴──┐
│   RED   │───▶│  GREEN  │───▶│ REFACTOR  │
│  Write  │    │  Make   │    │  Clean    │
│ failing │    │   it    │    │   up      │
│  test   │    │  pass   │    │  code     │
└─────────┘    └─────────┘    └───────────┘

TDD Best Practices

  1. Write the test first - Don't write production code without a failing test
  2. Write the minimal test - One behavior per test
  3. Write the minimal code - Just enough to pass
  4. Refactor ruthlessly - Clean up after green
  5. Run tests frequently - After every small change

TDD Example Flow

# Step 1: RED - Write failing test
def test_calculate_total_with_discount():
    order = Order(items=[Item(price=100)])
    order.apply_discount(10)  # 10%
    assert order.total() == 90

# Step 2: GREEN - Minimal implementation
class Order:
    def __init__(self, items):
        self.items = items
        self.discount = 0

    def apply_discount(self, percent):
        self.discount = percent

    def total(self):
        subtotal = sum(i.price for i in self.items)
        return subtotal * (100 - self.discount) / 100

# Step 3: REFACTOR - Clean up (if needed)

Behavior-Driven Development (BDD)

Gherkin Syntax

Feature: Shopping Cart
  As a customer
  I want to add items to my cart
  So that I can purchase them later

  Scenario: Add item to empty cart
    Given I have an empty cart
    When I add a product "Widget" priced at $10
    Then my cart should contain 1 item
    And my cart total should be $10

  Scenario: Apply discount code
    Given I have a cart with total $100
    When I apply discount code "SAVE10"
    Then my cart total should be $90

BDD Benefits

  • Tests as documentation
  • Shared language with stakeholders
  • Focus on behavior, not implementation
  • Easy to understand test intent

Test Design Patterns

Arrange-Act-Assert (AAA)

def test_user_registration():
    # Arrange - Set up preconditions
    user_data = {"email": "test@example.com", "password": "secure123"}
    user_service = UserService(mock_repository)

    # Act - Perform the action
    result = user_service.register(user_data)

    # Assert - Verify the outcome
    assert result.success is True
    assert result.user.email == "test@example.com"

Given-When-Then (BDD style)

def test_order_cancellation():
    # Given - a confirmed order
    order = create_confirmed_order()

    # When - the customer cancels it
    order.cancel()

    # Then - the order is cancelled and refund initiated
    assert order.status == "cancelled"
    assert order.refund_initiated is True

Test Data Builders

class UserBuilder:
    def __init__(self):
        self.email = "default@test.com"
        self.name = "Test User"
        self.role = "user"

    def with_email(self, email):
        self.email = email
        return self

    def with_role(self, role):
        self.role = role
        return self

    def build(self):
        return User(email=self.email, name=self.name, role=self.role)

# Usage
admin = UserBuilder().with_role("admin").build()

Object Mother Pattern

class TestUsers:
    @staticmethod
    def admin():
        return User(email="admin@test.com", role="admin")

    @staticmethod
    def customer():
        return User(email="customer@test.com", role="customer")

    @staticmethod
    def guest():
        return User(email=None, role="guest")

Mocking Strategies

When to Mock

MockDon't Mock
External APIsPure business logic
Database (for unit tests)Simple value objects
File systemDeterministic functions
Time/randomCore domain entities
Third-party servicesInternal collaborators (usually)

Mock Types

TypePurposeExample
StubReturn canned responsesmock.return_value = 42
MockVerify interactionsmock.assert_called_with(...)
SpyTrack real callsWraps real object, records calls
FakeSimplified implementationIn-memory database

Mocking Example

# Using unittest.mock
from unittest.mock import Mock, patch

def test_send_email_on_registration():
    # Arrange
    mock_email_service = Mock()
    user_service = UserService(email_service=mock_email_service)

    # Act
    user_service.register({"email": "test@example.com"})

    # Assert
    mock_email_service.send_welcome_email.assert_called_once_with("test@example.com")

# Using patch decorator
@patch("app.services.EmailService")
def test_with_patch(mock_email_class):
    mock_email_class.return_value.send.return_value = True
    # Test code...

Integration Test Patterns

Database Tests

import pytest
from testcontainers.postgres import PostgresContainer

@pytest.fixture(scope="session")
def database():
    with PostgresContainer("postgres:15") as postgres:
        yield postgres.get_connection_url()

def test_user_persistence(database):
    repo = UserRepository(database)
    user = User(email="test@example.com")

    repo.save(user)
    retrieved = repo.find_by_email("test@example.com")

    assert retrieved.email == user.email

API Tests

def test_create_user_endpoint(client):
    response = client.post("/api/users", json={
        "email": "new@example.com",
        "password": "secure123"
    })

    assert response.status_code == 201
    assert response.json["email"] == "new@example.com"
    assert "id" in response.json

E2E Test Patterns

Page Object Model

class LoginPage:
    def __init__(self, page):
        self.page = page
        self.email_input = page.locator("#email")
        self.password_input = page.locator("#password")
        self.submit_button = page.locator("button[type=submit]")

    def login(self, email, password):
        self.email_input.fill(email)
        self.password_input.fill(password)
        self.submit_button.click()
        return DashboardPage(self.page)

# Usage
def test_successful_login(page):
    login_page = LoginPage(page)
    dashboard = login_page.login("user@example.com", "password")
    assert dashboard.welcome_message.is_visible()

E2E Best Practices

  1. Use stable selectors - data-testid, not CSS classes
  2. Wait for conditions - Not arbitrary sleeps
  3. Isolate test data - Each test gets fresh data
  4. Test critical paths - Happy paths, key user journeys
  5. Keep them fast - Parallelize, minimize scope

Test Coverage Strategy

What to Cover

PriorityWhatWhy
HighBusiness logicCore value
HighEdge casesWhere bugs hide
HighError pathsGraceful failures
MediumIntegration pointsContract validation
LowUI layoutBrittle, low value
LowThird-party codeNot your responsibility

Coverage Metrics

MetricTargetNotes
Line coverage70-80%Basic minimum
Branch coverage60-70%Catches conditionals
Mutation score50-70%Measures test quality

Meaningful Coverage

HIGH VALUE:
  ✓ Core business logic
  ✓ Data transformations
  ✓ Error handling
  ✓ Security-sensitive code

LOW VALUE:
  ✗ Getters/setters
  ✗ Constructor-only classes
  ✗ Framework boilerplate
  ✗ Configuration files

Handling Flaky Tests

Common Causes

CauseSolution
Timing issuesUse explicit waits, not sleep
Shared stateIsolate test data
External dependenciesMock or use containers
Race conditionsAdd synchronization
Date/timeMock time providers
Random dataSeed random generators

Flaky Test Checklist

  • Is the test relying on timing?
  • Is there shared state between tests?
  • Is there an external dependency?
  • Is the order of execution assumed?
  • Is there non-deterministic data?

Test Organization

File Structure

tests/
├── unit/                    # Unit tests
│   ├── services/
│   │   └── test_user_service.py
│   └── models/
│       └── test_order.py
├── integration/             # Integration tests
│   ├── api/
│   │   └── test_user_endpoints.py
│   └── repositories/
│       └── test_user_repository.py
├── e2e/                     # End-to-end tests
│   └── test_checkout_flow.py
├── fixtures/                # Shared fixtures
│   └── factories.py
└── conftest.py              # Pytest configuration

Naming Conventions

# Pattern: test_[what]_[condition]_[expected]

def test_calculate_total_with_discount_returns_reduced_price():
    pass

def test_login_with_invalid_password_raises_auth_error():
    pass

def test_order_when_cancelled_sends_refund_notification():
    pass

Anti-Patterns to Avoid

  1. Testing implementation, not behavior - Tests break on refactor
  2. Large test methods - Hard to debug, unclear intent
  3. Excessive mocking - Tests don't reflect reality
  4. Shared mutable state - Tests affect each other
  5. Ignoring test failures - Broken windows effect
  6. Testing private methods - Coupling to implementation
  7. No assertion - Tests that can't fail
  8. Copy-paste tests - Maintenance nightmare

Quick Reference

PYRAMID:
  Unit (70%) → Integration (20%) → E2E (10%)

TDD CYCLE:
  Red → Green → Refactor

PATTERNS:
  AAA: Arrange-Act-Assert
  Builder: Fluent test data creation
  Page Object: E2E abstraction

MOCK WHEN:
  External APIs, Database (unit), Time, Random

COVERAGE:
  70-80% line, focus on business logic

NAMING:
  test_[what]_[condition]_[expected]

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.