mcpField
C
clean-tests

clean-tests

github.com/ertugrul-dmrテスト・品質208114 回インストール27 週間前に更新
リポジトリ

clean-tests について

clean-testsは、信頼性と保守性の高いテストを目指す開発者向けのテスト実践スキルです。カバレッジ、境界条件、テスト構成、失敗パターン、実行速度を扱います。

主な機能

  1. 01境界条件をテスト
  2. 02カバレッジツールで不足箇所を確認
  3. 03簡単なテストも残しスキップを解消
  4. 04失敗パターンを分析
  5. 05テストごとに概念を一つ扱う
  6. 06高速で独立したテストを維持

活用シーン

  1. 01境界条件の漏れをテストスイートで確認
  2. 02カバレッジ結果から未テストコードを特定
  3. 03繰り返すテスト失敗を診断
  4. 04テスト速度と構成を改善

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ertugrul-dmr/clean-code-skills --skill clean-tests

インストール後、Claude Code で/clean-testsを入力して読み込まれたか確認します。

詳細

クリーンなテスト

T1:テストが不十分

壊れる可能性のあるものはすべてテストしてください。カバレッジツールは目標ではなく、指針として使ってください。

# 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:カバレッジツールを使う

カバレッジツールは、テスト戦略の抜け漏れを報告します。無視しないでください。

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

# Aim for meaningful coverage, not 100%

T3:些細なテストも省略しない

些細なテストは動作を記録し、リグレッションを検出します。かかるコスト以上の価値があります。

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

T4:テストを無視するのは、曖昧さに関する疑問です

問題を隠すために @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():
    ...

T5:境界条件をテストする

バグは境界に集中します。明示的にテストしてください。

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:バグの周辺を徹底的にテストする

バグを見つけたら、類似するすべてのケースをテストしてください。バグは集中的に発生します。

# 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:失敗のパターンは多くのことを明らかにする

テストが失敗したら、パターンを探してください。根本的な問題を示していることがよくあります。

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

T8:テストカバレッジのパターンは多くのことを明らかにする

テストされていないコードパスを確認してください。設計上の問題が明らかになることがよくあります。

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

T9:テストは高速であるべき

遅いテストは実行されません。ユニットテストはそれぞれ100ms未満にしてください。

# 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"

テストの構成

F.I.R.S.T. の原則
  • Fast(高速):テストはすばやく実行できること
  • Independent(独立):テスト同士が依存しないこと
  • Repeatable(再現可能):どの環境でも毎回同じ結果になること
  • Self-Validating(自己検証可能):手動で確認しなくても、成功か失敗かがわかること
  • Timely(適時):コードの後ではなく、コードと同時か、それより前に書くこと
テストごとに1つの概念
# Bad - testing multiple things
def test_user():
    user = User("Alice", "[email protected]")
    assert user.name == "Alice"
    assert user.email == "[email protected]"
    assert user.is_valid()
    user.activate()
    assert user.is_active

# Good - one concept each
def test_user_stores_name():
    user = User("Alice", "[email protected]")
    assert user.name == "Alice"

def test_user_stores_email():
    user = User("Alice", "[email protected]")
    assert user.email == "[email protected]"

def test_new_user_is_valid():
    user = User("Alice", "[email protected]")
    assert user.is_valid()

def test_user_can_be_activated():
    user = User("Alice", "[email protected]")
    user.activate()
    assert user.is_active

クイックリファレンス

ルール原則
T1壊れる可能性のあるものはすべてテストする
T2カバレッジツールを使う
T3些細なテストも省略しない
T4無視されたテスト = 曖昧さに関する疑問
T5境界条件をテストする
T6バグの周辺を徹底的にテストする
T7失敗のパターンを探す
T8デバッグ時にカバレッジを確認する
T9テストは高速であること(<100ms)

コメント