TT Lab
Get started
Learn Learning paths Courses

Testing Tools in Practice

Filling In the Gaps in Coverage

Continue in TT Lab

Goal

You learn not how to write tests but how to choose what to test. You use coverage as a map, not as a goal.

Why it matters

100% coverage guarantees nothing. Even assert x is not None alone produces 100%. Conversely, the truly risky places (error handling, boundary values) are empty because writing tests was too much trouble, and that is exactly why bugs live there.

In this lab you find those gaps by the numbers and fill them, and at the end you finish by deciding what you will not fill.

Environment

pytest --cov=<모듈> --cov-report=term-missing
pytest --cov-branch      분기 커버리지
pytest --durations=5     느린 테스트 다섯 개

There is no network, but pytest, coverage, and hypothesis are included in the image.

Steps

  1. A function with three branches → /root/work/tt/billing.py
  2. Test only the normal path → test_billing.py
  3. Check the missing lines → /root/work/tt/03-cov.txt
  4. Fill in the error paths
  5. Branch coverage → /root/work/tt/05-branch.txt
  6. Verify a property with hypothesis
  7. The slow test → /root/work/tt/07-slow.txt
  8. What not to test → /root/work/tt/08-verdict.md

Notes

Create the code to test

A function with three branches → /root/work/tt/billing.py

Create /root/work/tt/billing.py. One function is enough: discount(price, rate) should (1) raise ValueError if rate is outside 0 to 1, (2) raise ValueError if price is negative, and (3) otherwise return a rounded integer. With three branches, the coverage is easy to read.

The first test

Test only the normal path → test_billing.py

Create test_billing.py in the same folder and test just one normal path. Make it pass with pytest -q. Do not touch the error paths yet; in the next step coverage will point them out.

Look at the missing lines

Check the missing lines → /root/work/tt/03-cov.txt

Run pytest --cov=billing --cov-report=term-missing -q and save the result to /root/work/tt/03-cov.txt. The line numbers of the error-handling lines must appear in the Missing column. The answer is not the number but those line numbers.

Fill in the gaps

Fill in the error paths

Add tests for the two error paths. Use pytest.raises(ValueError). When you measure again, coverage should be 100%.

Branch coverage is different

Branch coverage → /root/work/tt/05-branch.txt

Measure again with pytest --cov=billing --cov-branch --cov-report=term-missing -q and save it to /root/work/tt/05-branch.txt. Even if line coverage is 100%, branch coverage may not be. Seeing that difference is the purpose.

Inputs people cannot think of

Verify a property with hypothesis

Write one property-based test with hypothesis. Use @given(st.integers(min_value=0, max_value=10**6), st.floats(min_value=0, max_value=1)) to verify a property such as "the result is always at most price". The difference is that you write down a rule instead of listing examples.

Pick out the slow tests

The slow test → /root/work/tt/07-slow.txt

Look at the five slowest with pytest --durations=5 -q. Save the result to /root/work/tt/07-slow.txt. A slow test ends up not being run, and a test that is not run is worse than none.

Decide what not to test

What not to test → /root/work/tt/08-verdict.md

Write three lines in /root/work/tt/08-verdict.md: (1) what must be tested in this module, (2) what you decided not to test, and (3) why. The conclusion of this lab is not to make 100% the goal.