# testing-and-debugging Make targets for testing, debugging, and CI investigation. **Use these instead of raw `pytest`, `ruff`, or `actionlint` commands.** ## Why Make Targets Make targets encapsulate the correct venv activation, PYTHONPATH, env vars, and flags. Running raw commands bypasses venv activation and produces false failures (missing dependencies, wrong Python version). ## Unit Tests | Task | Command | Notes | |------|---------|-------| | Run all unit tests | `make test-unit` | Fast, no coverage | | Run with coverage | `make pytest-cov` | **Required before push** — enforces 100% | | Run single test | `make pytest-cov TEST=tests/test_foo.py::test_bar` | | | Check test speed | `make check-test-speed` | Fails if tests > 10s total or > 0.5s each | | Check test coverage | `make check-test-coverage` | Fails if source changed but tests didn't | ## Linting | Task | Command | Notes | |------|---------|-------| | Full lint | `make lint-all` | ruff + workflow-lint + lint-dockerfiles | | Ruff only | `make lint-ruff` | | | Format check | `make lint-format` | | | Type check | `make typecheck` | pyright | | Bandit | `make lint-bandit` | Security linter | | Workflow lint | `make workflow-check` | actionlint + act_runner dry-run | | Dockerfile lint | `make lint-dockerfiles` | hadolint on all Dockerfiles | | Check mutable globals | `make check-mutable-globals` | Detects module-level mutable state | | Check dep docs | `make check-dep-docs` | Verifies pyproject.toml deps have comments | ## Pre-Push Verification **Before pushing any branch:** ```bash make pre-push ``` This runs `lint-all` + `pytest-cov`. The pre-push git hook only validates the Vikunja task exists — it does NOT run tests. You must run `make pre-push` manually. ### Spec-Driven Workflow Every PR requires a spec file at `docs/specs/.md`. See the `spec-driven-development` skill for the full workflow and template. CI validates the spec (via `devx.ci.validate_spec`) and checks PR size (via `devx.ci.check_pr_size`) before running expensive jobs. ## CI Failure Investigation When investigating a CI failure: 1. **Fetch logs via MCP** — use `mcp_call_tool` with gitea server, `actions_run_read` method, `download_job_log` tool 2. **Reproduce locally** — use `make pytest-cov` or `make lint-all` depending on which CI job failed 3. **Never run raw pytest** — always use the make target ## Virtual Environment All commands run inside `.venv`. `make` targets handle activation automatically. For raw commands (rare), activate first: ```bash source activate.sh # bash/zsh source activate.fish # fish source activate.zsh # zsh ``` If `.venv` doesn't exist, run `make setup` first. ## Common Pitfalls ### Coverage Verification Before Push **Always run `make pytest-cov` before pushing** — CI enforces 100% coverage and will fail the PR if any lines are uncovered. This is the most common cause of CI quality job failures after code changes. The pre-push git hook only validates Vikunja task existence, not tests. ### API Response Type Checking Never use `is True`/`is False` identity checks on API response values. Many APIs return boolean values as strings (`"true"`/`"false"`). Use the `is_truthy()`/`is_falsy()` helpers from `devx.utils.api` or compare against string values. ### Time Mocking in Tests Always mock `time.sleep` and `time.monotonic` in unit tests using `@patch` decorators. Real sleep calls make tests slow and exceed test speed limits (10s total, 0.5s per test). ### Mutable Global State The `check-mutable-globals` tool detects module-level mutable state (lists, dicts, sets) that can cause test pollution. Avoid module-level mutable defaults — use factory functions or `None` with initialization inside functions.