Clean Tests logo

Clean Tests

Community
ertugrul-dmr
clean-tests

Use when writing, fixing, editing, or refactoring Python tests. Enforces Clean Code principles—fast tests, boundary coverage, one assert per test.

Overview

Publisherertugrul-dmr
Repositoryclean-code-skills
Skill nameclean-tests
Stars
203
Forks
35
Bundled files
Instructions only
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by ertugrul-dmr on GitHub. Read the source before you install it.

Installation

Install the Clean Tests AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/ertugrul-dmr/clean-code-skills/tree/main/skills/python/clean-tests
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/ertugrul-dmr/clean-code-skills.git /tmp/clean-code-skills
mkdir -p .claude/skills
cp -r /tmp/clean-code-skills/skills/python/clean-tests .claude/skills/clean-tests
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Clean Tests in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Clean Tests on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Clean Tests is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Clean Tests

T1: Insufficient Tests

Test everything that could possibly break. Use coverage tools as a guide, not a goal.

python
# Bad - only tests happy path
def test_divide():
    assert divide(10, 2) == 5

# Good - tests edge cases too
def test_divide_normal():
    assert divide(10, 2) == 5

def test_divide_by_zero():
    with pytest.raises(ZeroDivisionError):
        divide(10, 0)

def test_divide_negative():
    assert divide(-10, 2) == -5

T2: Use a Coverage Tool

Coverage tools report gaps in your testing strategy. Don't ignore them.

bash
# Run with coverage
pytest --cov=myproject --cov-report=term-missing

# Aim for meaningful coverage, not 100%

T3: Don't Skip Trivial Tests

Trivial tests document behavior and catch regressions. They're worth more than their cost.

python
# Worth having - documents expected behavior
def test_user_default_role():
    user = User(name="Alice")
    assert user.role == "member"

T4: An Ignored Test Is a Question About an Ambiguity

Don't use @pytest.mark.skip to hide problems. Either fix the test or delete it.

python
# Bad - hiding a problem
@pytest.mark.skip(reason="flaky, fix later")
def test_async_operation():
    ...

# Good - either fix it or document why it's skipped
@pytest.mark.skip(reason="Requires Redis, see CONTRIBUTING.md for setup")
def test_cache_invalidation():
    ...

T5: Test Boundary Conditions

Bugs congregate at boundaries. Test them explicitly.

python
def test_pagination_boundaries():
    items = list(range(100))
    
    # First page
    assert paginate(items, page=1, size=10) == items[0:10]
    
    # Last page
    assert paginate(items, page=10, size=10) == items[90:100]
    
    # Beyond last page
    assert paginate(items, page=11, size=10) == []
    
    # Page zero (invalid)
    with pytest.raises(ValueError):
        paginate(items, page=0, size=10)
    
    # Empty list
    assert paginate([], page=1, size=10) == []

T6: Exhaustively Test Near Bugs

When you find a bug, write tests for all similar cases. Bugs cluster.

python
# Found bug: off-by-one in date calculation
# Now test ALL date boundaries
def test_month_boundaries():
    assert last_day_of_month(2024, 1) == 31  # January
    assert last_day_of_month(2024, 2) == 29  # Leap year February
    assert last_day_of_month(2023, 2) == 28  # Non-leap February
    assert last_day_of_month(2024, 4) == 30  # 30-day month
    assert last_day_of_month(2024, 12) == 31 # December

T7: Patterns of Failure Are Revealing

When tests fail, look for patterns. They often point to deeper issues.

python
# If all async tests fail intermittently,
# the problem isn't the tests—it's the async handling

T8: Test Coverage Patterns Can Be Revealing

Look at which code paths are untested. Often they reveal design problems.

python
# If you can't easily test a function, it probably does too much
# Refactor for testability

T9: Tests Should Be Fast

Slow tests don't get run. Keep unit tests under 100ms each.

python
# Bad - hits real database
def test_user_creation():
    db = connect_to_database()  # Slow!
    user = db.create_user("Alice")
    assert user.name == "Alice"

# Good - uses mock or in-memory
def test_user_creation():
    db = InMemoryDatabase()
    user = db.create_user("Alice")
    assert user.name == "Alice"

Test Organization

F.I.R.S.T. Principles

  • Fast: Tests should run quickly
  • Independent: Tests shouldn't depend on each other
  • Repeatable: Same result every time, any environment
  • Self-Validating: Pass or fail, no manual inspection
  • Timely: Written before or with the code, not after

One Concept Per Test

python
# Bad - testing multiple things
def test_user():
    user = User("Alice", "alice@example.com")
    assert user.name == "Alice"
    assert user.email == "alice@example.com"
    assert user.is_valid()
    user.activate()
    assert user.is_active

# Good - one concept each
def test_user_stores_name():
    user = User("Alice", "alice@example.com")
    assert user.name == "Alice"

def test_user_stores_email():
    user = User("Alice", "alice@example.com")
    assert user.email == "alice@example.com"

def test_new_user_is_valid():
    user = User("Alice", "alice@example.com")
    assert user.is_valid()

def test_user_can_be_activated():
    user = User("Alice", "alice@example.com")
    user.activate()
    assert user.is_active

Quick Reference

RulePrinciple
T1Test everything that could break
T2Use coverage tools
T3Don't skip trivial tests
T4Ignored test = ambiguity question
T5Test boundary conditions
T6Exhaustively test near bugs
T7Look for patterns in failures
T8Check coverage when debugging
T9Tests must be fast (<100ms)

Frequently asked questions

What does the Clean Tests AI skill do?

Use when writing, fixing, editing, or refactoring Python tests. Enforces Clean Code principles—fast tests, boundary coverage, one assert per test.

Why use Clean Tests on TypingMind?

Because you install it once and use it with any model. Clean Tests is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Clean Tests in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/ertugrul-dmr/clean-code-skills/tree/main/skills/python/clean-tests. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Clean Tests?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Clean Tests?

As many as you like. As long as a model supports skills, you can use Clean Tests with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Clean Tests AI skill free?

Yes. It is published on GitHub by ertugrul-dmr under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇