3.7 KiB
Testing sendmsg
The test suite lives in tests/test_sendmsg.py and covers phone/group
detection, path expansion, attachment validation, Signal payload
construction, CSV parsing and dispatch (BOM handling, comma repair, blank
rows, skips, dry run, --json output), and CLI argument validation.
Requirements
- Python 3.10 or newer
pytest(the only test dependency — sendmsg itself is stdlib-only)
pip install pytest
# or on a system where pip refuses to touch system packages (Homebrew, Debian):
pip install pytest --break-system-packages
# or keep it isolated:
python3 -m venv .venv && source .venv/bin/activate && pip install pytest
Running the tests
Run from the repository root (the tests locate the sendmsg script
relative to their own path, so the working directory doesn't actually
matter — but the root is the natural place):
python3 -m pytest tests/
Expected output looks like:
..................................................................... [100%]
69 passed in 0.14s
Useful variations
python3 -m pytest tests/ -v # one line per test, with names
python3 -m pytest tests/ -q # terse summary only
python3 -m pytest tests/ -k csv # only tests matching "csv"
python3 -m pytest tests/ -k "bom or comma" # match multiple keywords
python3 -m pytest tests/test_sendmsg.py::TestPhoneNumbers # one test class
python3 -m pytest tests/test_sendmsg.py::TestCsv::test_quoted_commas_in_message # one test
python3 -m pytest tests/ -x # stop at the first failure
python3 -m pytest tests/ --lf # re-run only what failed last time
What the tests do NOT need
- No running signal-cli-rest-api container. All network calls
(
signal_rest_post,signal_rest_get) are replaced with fakes; the suite asserts on the payloads sendmsg would send. - No macOS / no
imsg. SMS sends are stubbed the same way, so the suite runs identically on Linux and macOS. - No real config. The suite pins
SIGNAL_REST_URLandSIGNAL_ACCOUNTenvironment variables before importing the script, so your real~/.sendmsg.confand shell environment can't leak into (or be touched by) test runs. Nothing is ever actually sent.
How the script gets imported
sendmsg has no .py extension, so the suite loads it with
importlib's SourceFileLoader (see the top of tests/test_sendmsg.py).
The loaded module is a normal Python module — tests call its functions
(normalize_account, send_one_signal, cmd_csv via main(), ...)
directly and monkeypatch its globals.
Two consequences worth knowing:
- Module-level code (config loading) runs at import time — that's why the env vars are pinned first.
- If you rename or move the
sendmsgscript, updateSCRIPT_PATHat the top of the test file.
Continuous integration
.github/workflows/ci.yml runs on every push and pull request:
a compile check (python -m py_compile sendmsg) followed by the full
suite on Python 3.10, 3.11, 3.12, and 3.13. A green run on your branch
means the same command that CI uses passed:
python -m py_compile sendmsg && python3 -m pytest tests/ -v
Adding tests
- Pure helpers (parsing, normalization, validation) get direct
parametrized tests — see
TestPhoneNumbersfor the pattern. - Anything that would send goes through the stubbing helpers:
run_csv()for CSV behavior (returns exit code, stdout, stderr, and the captured Signal/SMS calls) and thecaptured_postsfixture for payload-level assertions. - When fixing a bug, add a test that fails on the old behavior first — most tests in the suite carry a comment naming the bug they pin down.