Practical lab guide
Lab: build and test a configuration-reporting CLI
Combine validation, file handling, command output, and focused tests.
On this page
Assemble the fixture
Use Python 3.11 or newer. Place capacity.py, read_capacity.py, and capacity_cli.py from the preceding bites in one new directory. Add a tests directory. The tool reports a supplied capacity fixture; it does not inspect or modify your actual disk.
Save tests/test_capacity.py:
import json
import tempfile
import unittest
from pathlib import Path
from capacity import remaining_gib
from read_capacity import read_capacity
class CapacityTests(unittest.TestCase):
def test_remaining(self):
self.assertEqual(remaining_gib(20, 8), 12)
def test_rejects_invalid_range(self):
with self.assertRaises(ValueError):
remaining_gib(20, 21)
def test_rejects_boolean(self):
with self.assertRaises(TypeError):
remaining_gib(20, True)
def test_reads_file(self):
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / 'capacity.json'
path.write_text(json.dumps({'total': 20, 'used': 8}), encoding='utf-8')
self.assertEqual(read_capacity(path), 12)
def test_rejects_unknown_field(self):
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / 'capacity.json'
path.write_text('{"total":20,"used":8,"extra":0}', encoding='utf-8')
with self.assertRaises(ValueError):
read_capacity(path)
From the project root, run python3 -m unittest discover -s tests -p 'test_capacity.py' -v. Confirm that five capacity tests were discovered. Change one expected value temporarily and verify the suite fails, then restore it. This is a useful check that the test invocation actually executes assertions.
Read what each test establishes
The first test checks the known calculation. The next two make invalid input observable, including Python's otherwise surprising treatment of booleans as integers. The file tests create isolated temporary directories, write only invented data, and remove those directories automatically when the context exits. They do not depend on your real disk capacity or a particular working directory's fixture file.
Use python3 -m unittest discover -s tests -p 'test_capacity.py' -v when you want exactly these five tests. If you retained the preceding HTTP lesson's test_status.py, unfiltered discovery also runs its two tests; that larger count is expected. A count of zero means discovery missed the files and is not a successful check of the tool.
Keep failure scope clear: rejecting a missing field is a file/schema check; accepting a valid calculation is a function check; returning the right exit code requires a CLI check. None of the five tests above launches the CLI process.
Exercise the CLI boundary
Run the CLI with a valid JSON fixture, a malformed JSON file, a missing file, and no argument. Capture stdout, stderr, and exit status separately. Add tests for these boundary behaviors as an extension; the five tests above do not yet test the subprocess interface.
Complete the loopback HTTP exercise independently. Record which failures were parser errors and which required a running service. Do not add cloud credentials to this tool.
Checkpoint and cleanup
Explain why importing the calculation module does not run its example loop, why a parsed JSON object still needs validation, and why failure must propagate to the caller. Keep a README with the exact invocation, output schema, and limitations.
Temporary directories inside the tests clean themselves up. Stop any HTTP fixture and remove its named files. Retain this small project for the CI lab. Revision: pure logic, validated boundaries, useful errors, real assertions, no external side effects in unit tests.
Answer the checkpoint
The main guard keeps the example loop out of imports. Parsing establishes JSON syntax, while our key/type/range checks establish this tool's expected data. A nonzero exit lets the shell or CI stop dependent work. These are three separate behaviors; point to the line implementing each rather than answering only with a definition.
For the CI lab, carry capacity.py, read_capacity.py, capacity_cli.py, and tests/test_capacity.py into the practice repository. The HTTP fixture and its tests can remain a separate extension. Do not copy .venv, temporary output files, or credentials.
Apply this to MicroBank
After the six foundations modules, apply Python to the real local transaction flow. Start with the project setup and follow its ordered steps; later implementation stages depend on the earlier files.
Sources and practice status
Primary references: unittest↗; TemporaryDirectory↗.
Reviewed against documentation on 1 October 2026. The exercises still need to be run in your environment. Record your results and tool versions in your notes.
Your notes and evidence
Record observations, questions, or links to your work. Keep credentials out of your notes.
Back up or restore this path
Progress and notes stay in this browser. A backup contains only this learning path.