Skip to content

cross-refactoring: テストを足す項目(add-tests)が pytest の収集しないファイルへテストを足し、実行されないまま検証を通る #620

Open

Description

@takemi-ohama

何を見つけたか

/ndf:cross-refactoring がpytest の全体の実行が収集しないファイル(test_*.py の名前を持たない補助モジュール)へ現状固定テストを足しても、検証を通る。足したテストは全体テストと CI では走らず、何も固定しない。

今の形(develop edf4036、ndf 10.17.67)

1 回の計画の add-tests のフェーズが、足したテストを確かめる(plugins/ndf/skills/cross-refactoring/scripts/refactor_lib/commands/implement.py の _run_added_tests、決定 13)。確かめ方はファイルのパスを範囲テストの雛形へ明示で渡すため、pytest は test_*.py の名前でない補助モジュールも収集して走らせる。

$ pytest tests/helpers.py   # 失敗するテストを置いた補助モジュールを明示で渡す
1 failed
$ pytest tests              # 全体の実行
no tests ran

足したテストは add-tests の確認では 1 回走るが、全体テストと CI では収集されず、以後の項目の変更を固定しない。refactor_lib/pathkinds.py:76 の is_test_path は、ディレクトリの印があれば中身を読まずにテストとして扱い、ファイル名の印だけで当たった .py は中身にテストの関数があるかを見る(#2516 決定 3)。どちらの経路も収集の対象かは見ない。

最初の観測: PR #612(issue #500、文書の改名と手入れ)

  • --scope にテストの置き場所が要るため、改名の追随で 1 行だけ触る scripts/tests/doc_staleness_helpers.py を入れた
  • テスト整備ラウンド 1 の R1-001(codex が適用)がコミット fa6ec5b「Test: edit のエラー経路を現状固定」で、そのファイルへ 16 行のテストを足した
  • doc_staleness_helpers.py は他のテストが import する補助で、pytest の収集の対象ではない。足した関数は実行されない
  • 進行側が気づいて中止し、9dcf24e で revert した(改修計画: Docs: README.md を規約の役割へ合わせ、Skill 執筆規約を AUTHORING.md へ改名する(#500) #612 (comment) )

どこで見つけたか

なぜこの変更の範囲外なのか

#500 は README の規約への合わせ込みで、cross-refactoring の振る舞いは受け入れ条件に含まれない。PR 本文には中止の理由として残したが、課題としては起票されていなかった(振り返りで取りこぼしとして拾った)。

直さないと何が起きるか

現状固定テストが「足された」と記録されるのに、何も固定していない。 以後の項目の実装と全体テスト・CI は、固定されていない振る舞いを変えても通る。改修計画には採用・適用の記録が残るため、読む側は守られていると受け取る。

今回は文書だけの変更で中止したため実害は無いが、コードの変更で同じ置き場所の選び方をすると気づく手がかりが無い。足したテストの件数が、実行されたテストの件数に表れているかを確かめれば機械で拾える。

修正レイヤー

足したテストが全体の実行に入るかの検証は、add-tests の確認(plugins/ndf/skills/cross-refactoring/scripts/refactor_lib/commands/implement.py の _run_added_tests)に置く。
明示のパスで走らせる確認では、収集の対象かを見分けられない。テストファイルの判定(refactor_lib/pathkinds.py:76 の is_test_path)は
ディレクトリの印(TEST_PATH_MARKERS、:14)があれば中身を読まないため、tests/ 配下の補助モジュールもテストとして扱う。

  • 確かめ方: 全体の実行の集合(--collect-only など)と足したテストを突き合わせる
  • 収集の規則(どのファイルが実行の集合に入るか)は、宣言(.ndf/project.json の test.suites)を読む plugins/ndf/scripts/lib/test_strategy.py から得る。cross-refactoring の中に収集の規則を写さない
  • test_strategy.py は今、suite ごとに runner・command(全体の実行)・scope_command・paths を持ち、収集の規則は持たない。全体の実行の集合を得る方法(command に収集だけの選択肢を足して走らせる・runner ごとの規則を持たせる など)は設計で決める

受け入れ条件

着手の条件

無し。

由来

PR #617(ndf v10.11.0 の配布)の振り返り。発生は PR #612(issue #500)。

関連

再確認(ndf 10.22.0、2026-10-25)

  • 現象は 10.22.0 でも再現する。repo の pytest.ini で失敗するテストを tests/helpers.py に置くと、pytest tests/helpers.py は 1 failed(exit 1)、pytest tests は no tests ran(exit 5)。commands/implement.py の _run_added_tests と targets.valid_targets に、収集の対象かを見る処理は無い

  • 2026-10-10 以降に Item-Id を持つコミット 107 件(件名が Test のもの 17 件)で、test_*.py でないテスト置き場の .py へ入ったものは 0 件

  • 現象は今も再現する。pytest.ini を写した一時ディレクトリで、失敗するテストを入れた tests/helpers.py は明示のパスなら 1 failed(exit 1)、pytest tests では no tests collected(exit 5)になる。範囲テストのコマンドは補助モジュールを明示のパスで渡す(scope_runs が pytest plugins/ndf/scripts/tests/gh_fake.py … を組む)

  • _run_added_tests・_added_test_commands(implement.py)と targets.valid_targets に、収集の対象かを見る処理は無い

  • 再発: 2026-09-13 以降に Item-Id を持つテストのコミット 246 件のうち、補助モジュールへ入ったのは最初の観測(fa6ec5b59、revert 済み)の 1 件だけ

  • 確かめ方の候補は --collect-only のほかに 2 つある。どれを採るかは設計で決める

    • (a) 宣言の suite が持つ junit(.ndf/tmp/junit.xml)に、足したテストのファイルが現れるかを突き合わせる。cross-refactoring は scope_verdict.py と test_triage.read_junit で junit を読んでいるため、runner ごとの収集の規則を写さずに済む。判定は全体テストの時点(着手前・危険フラグ・最終ゲート)まで遅れる
    • (b) 計画の時点で、test_targets が収集の対象外なら valid_targets で落とす

Activity

  1. modified the milestones: 06 収束ループの起動と実行の安全, , 17 トークン消費の削減 on Sep 22, 2026
  2. changed the title [-]cross-refactoring: テスト整備ラウンドが pytest の収集しないファイルへテストを足し、実行されないまま検証を通る[/-] [+]cross-refactoring: テストを足す項目(add-tests)が pytest の収集しないファイルへテストを足し、実行されないまま検証を通る[/+] on Sep 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ndf-skillNDF の Skill 本体bugSomething isn't workingpriority: medium保守性・設計一貫性など、計画的に対応する

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions