Skip to content

Commit 380727e

Browse files
authored
Update CONTRIBUTING.md with better content
1 parent 783954f commit 380727e

1 file changed

Lines changed: 19 additions & 12 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,39 @@
33
Found an issue with an exercise, or have an idea for a new one? Open an issue first before writing any code — it saves everyone rework if the idea doesn't fit the curriculum sequence.
44

55
## How tests look like for beginner exercises
6-
Let's look at the test file first:
7-
86
```python
97
def test_prints_hello_world(run_script):
108
stdout, _ = run_script("hello_world.py")
119
assert stdout.strip() == "Hello, World!"
1210
```
1311

14-
`run_script` is a helper set up once for the whole repo. It runs `hello_world.py` exactly the way Python would if you typed `python hello_world.py`, and hands back everything it printed. The test then checks that what got printed matches `'Hello, World!'` exactly — capitalization and punctuation included.
12+
### Fixtures
13+
Raw pytest failures (`IndexError`, `assert '' == 'Hello, World!'`) are confusing before you know what a list or an assertion diff even is. Script-style tests instead use four shared helpers from `conftest.py`.
14+
15+
We have implemented a few custom functions (*fixtures*) built to make errors less scary for students. Please use these until later exercises where students cover specific erorrs and how to handle them.
1516

17+
* `run_script` - Run a .py file exactly as `python <file>` would, and capture its output.
18+
* `expect_output` - Assert a script's entire printed output matches exactly, with a
19+
plain-language failure message instead of pytest's default diff.
20+
* `expect_line` - Assert that a specific (1-indexed) line of a script's output matches
21+
exactly, with a plain-language message — including when the script
22+
hasn't printed that many lines yet, instead of a raw `IndexError`.
23+
* `expect_variables` - Assert that several variables in a script's namespace all match
24+
expected values at once, with a single friendly summary of everything
25+
that's missing or wrong — instead of stopping at the first problem
26+
like `expect_variable` does.
27+
* `expect_variable_type` - Assert that a variable exists and is of a given type, without caring
28+
about its exact value — e.g. "is this a string" rather than "is this
29+
exactly 'hello'".
30+
31+
You can find more about these functions in their docstrings in [conftest.py file](https://github.com/ThePythonLedger/python-exercises/blob/main/conftest.py)
1632

1733
## Two exercise styles
1834

1935
Early exercises don't assume you know about functions yet, so they're written as **plain scripts** — top-level code you'd type straight into the terminal, no `def` or `import`. Their tests use a shared `run_script` fixture (see `conftest.py`) that runs the file exactly like `python <file>.py` and checks what it printed.
2036

2137
Once functions show up in the curriculum, exercises switch to the **function style** you may be more used to seeing: a stub function you fill in, imported directly into the test file. Each exercise's README says which style it is, but you can also tell from the stub file itself — a bare script vs. a `def`.
2238

23-
## Friendly failure messages
24-
25-
Raw pytest failures (`IndexError`, `assert '' == 'Hello, World!'`) are confusing before you know what a list or an assertion diff even is. Script-style tests instead use two shared helpers from `conftest.py`:
26-
27-
- `expect_output(stdout, "expected text")` — checks the whole printed output at once, and on failure says plainly what was expected vs. what actually printed.
28-
- `expect_line(stdout, line_number, "expected text")` — checks one line of output (1-indexed). If the script hasn't printed that many lines yet, it says so directly ("Have you added a print() statement for this part yet?") instead of raising `IndexError`.
29-
30-
Both suppress the Python traceback entirely — the learner only sees the message, not internal test code.
31-
3239
## Running everything at once
3340

3441
From the repo root, `pytest` (no arguments) will discover and run every non-skipped test in the repo — handy as a sanity check, but exercises are meant to be done one at a time.

0 commit comments

Comments
 (0)