如何讓現有測試替你選出第一個 PR
Let the Existing Tests Choose Your First PR
Quinn Zhu 提出以既有測試選定首個 PR 的流程,先界定一個可由測試回答的問題,再定位相關測試並記錄基線。流程建議只新增一項斷言,將改動限制在最多三個檔案,其中一個是測試,並在修改後重跑基線測試。若本機無法執行測試,可用 MonkeyCode 的免費伺服器選項作一次性工作區;貼上錯誤追蹤與測試名稱即可,不要傳送整個檔案或含機密的內容。
Your first pull request should be chosen by a test, not by curiosity.
Curiosity sends you to the files that are fun to read. Tests send you to the files that are safe to change. On day one you cannot tell those apart by reading alone.
This drill takes about an hour. It ends with one small PR and a baseline you can actually trust.
Step 0 — Fix your question in one sentence
Write the question down before you open a single source file.
A usable question looks like this: "Does invoice_total() include tax on refunds?" A useless one looks like: "How does billing work?" The first can be answered by a test. The second can absorb your whole week.
Keep the question where you will see it. A line at the top of your scratch branch is enough.
Step 1 — Map which tests already name your file
Pick one candidate file. Then let git tell you who already checks its behavior.
Save this as name-the-test.sh in your scratch clone:
#!/usr/bin/env bash
# name-the-test.sh — find the tests that already mention a file you want to change.
# usage: ./name-the-test.sh src/billing/invoice.py
set -euo pipefail
target="${1:?usage: name-the-test.sh <path/to/file>}"
stem="$(basename "${target%.*}")"
echo "--- test files mentioning '${stem}' ---"
git grep -l -i -- "${stem}" -- '*test*' '*spec*' '*__tests__*' || echo "(none)"
echo "--- tracked files in the same family ---"
git ls-files | grep -i -- "${stem}" | grep -i -e test -e spec || echo "(none)"
echo "--- last three commits touching the file ---"
git log -3 --date=short --format='%h %ad %s' -- "${target}"
Run it against three candidate files, not one. You want options, not a commitment.
./name-the-test.sh src/billing/invoice.py
./name-the-test.sh src/billing/refund.py
./name-the-test.sh src/billing/tax_rules.py
If a file returns zero test references, drop it. A file nobody tests is a file where your mistake is invisible.
Step 2 — Run only those tests, and save the output
Do not guess the test command. Copy it from the repository's own CI config.
grep -rn -A3 'run:' .github/workflows/ | grep -i -e pytest -e 'npm test' -e 'go test'
Then run the single file you found, and write the output to disk:
python -m pytest tests/billing/test_invoice.py -q 2>&1 | tee /tmp/baseline.txt
tail -n 5 /tmp/baseline.txt
That file is now your baseline. Green or red, you know the starting state. Most first-PR confusion comes from never having captured it.
If the run fails on import errors rather than assertions, stop. You have an environment problem, not a code problem.
Step 3 — Turn your question into one assertion
Add a single test that answers your Step 0 sentence. Not three tests. One.
def test_refund_total_excludes_tax():
invoice = Invoice(amount=100, tax_rate=0.2, refunded=True)
assert invoice.total() == 100
Run it. It should fail, and the failure message should be readable enough for a stranger.
If the assertion cannot be written without mocking five collaborators, your question is too big. Shrink it until the test fits on one screen.
Step 4 — Make the smallest change that flips the test
One rule keeps first PRs reviewable: at most three files change, and one of them is the test.
If the fix needs a fourth file, split the ticket. State the split in the PR description rather than expanding scope quietly. Reviewers forgive small PRs and small questions; they rarely forgive a surprise refactor.
Re-run the baseline file after the change. Compare with /tmp/baseline.txt and confirm you moved only the test you meant to move.
Step 5 — When your laptop cannot run the suite
Some first days die on environment setup. Python 3.6 on a work laptop, an ARM machine, a Windows shell against a Linux-only suite. The drill above stalls at Step 2 through no fault of yours.
This is where I keep a disposable workspace instead of a permanent one. MonkeyCode offers free model access and a free server option, which is enough for a single-file test run and a failure explanation. Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Two habits make that safe:
- Send the failure output, not the whole file. Paste the traceback and the test name into the model. Ask "what does this assertion say about the code?" not "rewrite this module."
- Keep the free server ephemeral. Clone, run, copy the log back, throw the workspace away. Anything you would not put in a public gist does not belong there.
I am deliberately not quoting quota numbers or machine specs. Free tiers move, and a number printed in a blog post is stale within weeks. Check the project's own page on the day you need it.
The decision table
| Situation | Local clone | Free server workspace |
|---|---|---|
| Suite runs in under 2 minutes | Use local | Unnecessary |
| Suite needs a Linux-only binary | Skip | Reasonable |
Repo has secrets in .env fixtures |
Use local only | Do not use |
| You only need one test file | Use local | Fine either way |
| You need a long-lived CI replacement | Build real CI | Not this |
| You want to read a stack trace with help | Use local | Acceptable |
Treat the free server as a place to answer one question. The moment it becomes your only way to run tests, you have a dependency, not a tool.
What this drill does not do
name-the-test.sh is a grep heuristic. Dynamic imports, string-built module names, and reflection-based frameworks will hide tests from it. If it returns (none) for a file you know is covered, trust the code and check by hand.
It also assumes a test suite exists. Repositories with no tests need a different first hour, and that is a fair reason to ask your mentor before starting.
Finally, this drill will not teach you architecture. It teaches you where the safety net is. Reading the module top-to-bottom still has to happen, just not before you know which behavior someone already promised to protect.
If you try one thing from this post, try the ordered steps: question, grep, baseline, one assertion, one small diff. If your machine fights you on step two, the free server option is the lowest-stakes place to start.
來源:DEV Community · dev.to