agentsclimarketplace

Test writer

Skill oxhagolli/clawdskillz/skills/test-writer

Use this skill when writing unit tests or integration tests for code. Prefers integration tests that reflect real usage, keeps tests fast and simple, and avoids over-mocking. Trigger after implementing features or when adding test coverage.From its SKILL.md

Install
npx -y skills add oxhagolli/clawdskillz --skill test-writer

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 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

7.5 KB, as published. Nobody here has run it

Test Writer Protocol

Write tests that catch real bugs and run fast. Prefer integration tests. Keep it simple.

Core Principles

  • Integration over unit - Test how things work together, not internals
  • Real usage - Tests should look like how code is actually used
  • Fast tests - Slow tests are a permanent tax on the repo
  • Simple tests - If a test is hard to understand, it's hard to maintain
  • Pragmatic coverage - High coverage when it makes sense, don't chase numbers

Test Hierarchy

Prefer tests in this order:

1. Integration tests (best)
   - Test real components working together
   - Use real database, real HTTP calls (to test servers)
   - Catch the bugs that actually happen

2. Functional tests
   - Test a module's public interface
   - Real dependencies where reasonable
   - Mock only external services

3. Unit tests (use sparingly)
   - Only for complex pure logic
   - Algorithms, calculations, parsing
   - Avoid for simple glue code

Integration Test Philosophy

Test the whole flow:

# Good - tests real behavior
async def test_create_order():
    # Setup: real database, real service
    user = await create_test_user()
    product = await create_test_product(price=100)

    # Act: real API call or service call
    order = await order_service.create(user_id=user.id, product_id=product.id)

    # Assert: check real outcomes
    assert order.total == 100
    assert await db.orders.exists(order.id)
    assert user.balance_changed()
# Bad - tests nothing real
def test_create_order():
    mock_db = Mock()
    mock_user = Mock(id=1)
    mock_product = Mock(id=2, price=100)
    mock_db.orders.insert.return_value = Mock(id=99)

    # All you're testing is that mocks return what you told them to
    result = create_order(mock_db, mock_user, mock_product)
    assert result.id == 99  # Meaningless

When to Unit Test

Unit tests make sense for:

  • Pure functions with complex logic
  • Algorithms (sorting, parsing, calculations)
  • Edge case handling in isolated functions
  • Code that's genuinely independent
# Good unit test - pure logic
def test_calculate_discount():
    assert calculate_discount(100, percent=10) == 90
    assert calculate_discount(100, percent=0) == 100
    assert calculate_discount(0, percent=50) == 0

# Bad unit test - just testing wiring
def test_user_service_calls_repository():
    mock_repo = Mock()
    service = UserService(mock_repo)
    service.get_user(1)
    mock_repo.find.assert_called_with(1)  # Who cares?

Keep Tests Fast

Speed budget:

  • Unit test: < 10ms
  • Integration test: < 500ms
  • Full test suite: < 60 seconds (ideal), < 5 minutes (maximum)

How to stay fast:

# Use test database with fast resets
@pytest.fixture
async def db():
    async with test_database() as db:
        yield db
        # Cleanup is fast - truncate, don't recreate

# Parallelize where possible
# pytest-xdist, vitest --pool=threads

# Avoid unnecessary setup
# Don't create 100 users if you need 1

Slow test red flags:

  • Sleeping/waiting for time (time.sleep, setTimeout)
  • Starting/stopping servers per test
  • Network calls to external services
  • Large dataset generation

Fix slow tests:

# Bad - waits for real time
def test_cache_expires():
    cache.set("key", "value", ttl=60)
    time.sleep(61)
    assert cache.get("key") is None

# Good - mock time
def test_cache_expires(mock_time):
    cache.set("key", "value", ttl=60)
    mock_time.advance(61)
    assert cache.get("key") is None

Keep Tests Simple

One concept per test:

# Good - clear what's being tested
def test_user_can_place_order():
    ...

def test_user_cannot_order_out_of_stock_product():
    ...

def test_order_calculates_tax_correctly():
    ...

# Bad - tests everything at once
def test_order_system():
    # Creates user, product, order, checks tax, inventory, email...
    # If it fails, which part broke?

Readable assertions:

# Good
assert user.is_active
assert order.total == 150
assert "error" not in response.json()

# Bad
assert response.json()["data"]["user"]["status"]["active"] == True and \
       response.json()["data"]["order"]["totals"]["final"] == 150

Minimal setup:

# Good - only what matters
def test_discount_applied():
    order = Order(subtotal=100)
    order.apply_discount(10)
    assert order.total == 90

# Bad - irrelevant details
def test_discount_applied():
    user = User(name="John", email="[email protected]", created=datetime.now())
    product = Product(name="Widget", sku="W001", category="Tools")
    order = Order(user=user, products=[product], subtotal=100, ...)
    # None of this matters for testing discount logic

What to Mock (and What Not To)

Mock:

  • External APIs (payment providers, email services)
  • Time-dependent behavior
  • Random/non-deterministic operations
  • Services you don't control

Don't mock:

  • Your own database (use test DB)
  • Your own services (test them together)
  • Simple dependencies (just use the real thing)
  • Return values you're asserting against
# Good mocking - external service
@patch("stripe.Charge.create")
def test_payment_processed(mock_stripe):
    mock_stripe.return_value = {"id": "ch_123", "status": "succeeded"}
    result = process_payment(amount=100)
    assert result.success

# Bad mocking - your own code
@patch("myapp.services.user_service.get_user")
@patch("myapp.services.order_service.create_order")
def test_checkout(mock_user, mock_order):
    # You're not testing anything real

Coverage Philosophy

Don't chase numbers:

80% coverage with good tests > 100% coverage with bad tests

Cover what matters:

  • Business logic (revenue, security, data integrity)
  • Error paths that could fail silently
  • Integration points between components

Skip coverage for:

  • Boilerplate/glue code
  • Simple getters/setters
  • Generated code
  • Code that's obviously correct

When to increase coverage:

  • After a bug (add test that would have caught it)
  • For complex logic
  • For security-sensitive code

Response Format

When writing tests:

## Test Plan

**Type**: [Integration / Functional / Unit]
**Scope**: [What's being tested]

**Tests to write**:
1. [test_name] - [what it verifies]
2. [test_name] - [what it verifies]

**Mocking strategy**:
- External services: [what's mocked]
- Using real: [what's not mocked]

**Speed estimate**: [fast/medium/needs optimization]

Checklist

Before finishing tests:

  • Tests reflect real usage patterns
  • Integration tests for main flows
  • Unit tests only for complex pure logic
  • All tests run in < 500ms each
  • No unnecessary mocking
  • Each test has one clear purpose
  • Failures give useful error messages
  • No flaky/timing-dependent tests

Calibration

Prefer fewer, better tests. 10 meaningful integration tests beat 100 trivial unit tests.

Test behavior, not implementation. If you refactor and tests break but behavior didn't change, the tests were wrong.

Make failures obvious. A test that fails should tell you exactly what's wrong.

Stay in your lane. Don't cover:

  • Which edge cases to test (test-engineer)
  • Whether to build the feature (product-manager)
  • Code style/linting (linting-engineer)

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.