Loading...
Loading...
Use when writing, fixing, editing, or refactoring Python tests. Enforces Clean Code principles—fast tests, boundary coverage, one assert per test.
npx skill4agent add ertugrul-dmr/clean-code-skills clean-tests# 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# Run with coverage
pytest --cov=myproject --cov-report=term-missing
# Aim for meaningful coverage, not 100%# Worth having - documents expected behavior
def test_user_default_role():
user = User(name="Alice")
assert user.role == "member"@pytest.mark.skip# 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():
...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) == []# 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# If all async tests fail intermittently,
# the problem isn't the tests—it's the async handling# If you can't easily test a function, it probably does too much
# Refactor for testability# 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"# 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| Rule | Principle |
|---|---|
| T1 | Test everything that could break |
| T2 | Use coverage tools |
| T3 | Don't skip trivial tests |
| T4 | Ignored test = ambiguity question |
| T5 | Test boundary conditions |
| T6 | Exhaustively test near bugs |
| T7 | Look for patterns in failures |
| T8 | Check coverage when debugging |
| T9 | Tests must be fast (<100ms) |