Skip to content

test: raise test coverage to 100% and require it in CI#775

Merged
zkoppert merged 3 commits into
mainfrom
zkoppert/raise-coverage-to-100
Jun 12, 2026
Merged

test: raise test coverage to 100% and require it in CI#775
zkoppert merged 3 commits into
mainfrom
zkoppert/raise-coverage-to-100

Conversation

@zkoppert

@zkoppert zkoppert commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Pull Request

Proposed Changes

I added 35 targeted unit tests that cover branches the per-module test files were missing. Each new test class lives in the existing test_<module>.py file that matches the source module it exercises (for example, the SORT_ORDER fallback test went into test_config.py, the search rate-limit and exception tests went into test_search.py), matching the repo's existing per-module test file naming convention. All GitHub API interactions are mocked with unittest.mock (no network access).

Two production branches are structurally unreachable from real input. I annotated them with # pragma: no cover and an explanatory comment rather than writing phantom tests that mock them past:

  • markdown_writer.group_issues else-branch: the valid_fields = {"author", "assignee"} guard a few lines above returns early for any other value, so the else can never execute unless valid_fields is extended without updating the if/elif chain.
  • most_active_mentors.count_comments_per_user discussion branch: three layered defects make this path dead in production (GraphQL query fetches no comment author data, attribute access would AttributeError on dict nodes, and ignore_comment is called with comment.user as both issue_user and comment_user so the self-comparison always returns True). Tracked in Discussion mentor counting is dead code (GraphQL + ignore_comment self-reference + dict-vs-object mismatch) #774 for separate triage.

With those exclusions, I bumped --cov-fail-under in the Makefile from 80 to 100 so future drops in coverage fail CI immediately.

Before / after coverage

Coverage Tests
Before 91% (91 uncovered lines across 12 modules) 157
After 100% (all 19 source modules) 191

Testing

I ran make lint and make test end-to-end against Python 3.14 in a clean environment (matching the CI runner). All five linters pass (flake8 syntax + style, isort, pylint 10.00/10, mypy, black) and pytest reports 191 passing with Required test coverage of 100% reached. Total coverage: 100.00%.

Rollout

In this PR I only add tests, one source-code annotation, and a Makefile threshold bump. No runtime behavior changes for end users of the action. The blast radius is the CI gate itself: if a future PR's coverage drops below 100%, CI will fail until the contributor adds tests or, for genuinely unreachable defensive branches, a # pragma: no cover annotation with an explanatory comment.

What to watch after merge

I will watch the next few PRs from outside contributors for friction around the 100% coverage gate. If contributors hit the gate on legitimately defensive branches without realizing # pragma: no cover is the documented escape hatch, I will add a short note to CONTRIBUTING.md linking to the markdown_writer and most_active_mentors examples in this PR.

Readiness Checklist

Author/Contributor

  • If documentation is needed for this change, has that been included in this pull request
  • run make lint and fix any issues that you have introduced
  • run make test and ensure you have test coverage for the lines you are introducing

zkoppert and others added 2 commits June 11, 2026 22:52
I added 36 unit tests in test_coverage_additions.py that exercise
branches not previously hit by the per-module test files. Each test is
named to indicate the source file and line range it covers so future
maintainers can trace coverage gaps quickly.

All GitHub API interactions are mocked with unittest.mock (no network
access). Coverage rises from 91% to 100% across all modules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Zack Koppert <zkoppert@github.com>
Two production branches are not exercisable from real code paths but
are kept for safety; I marked them with '# pragma: no cover' and a
comment explaining why coverage cannot reach them through real input:

- markdown_writer.group_issues has an else-branch that is unreachable
  because the function returns early when group_by is not in
  valid_fields = {'author', 'assignee'} a few lines above.
- most_active_mentors.count_comments_per_user has a discussion branch
  that is structurally dead in production: the GraphQL query in
  discussions.get_discussions fetches no comment author data, the
  attribute access here would AttributeError on dict nodes, and
  ignore_comment is called with comment.user as both issue_user and
  comment_user (self-reference always True). Tracked in #774.

With the remaining production code 100% exercised by tests, I bumped
--cov-fail-under in the Makefile from 80 to 100 so future drops in
coverage fail CI immediately.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Zack Koppert <zkoppert@github.com>
@zkoppert zkoppert self-assigned this Jun 12, 2026
@zkoppert zkoppert marked this pull request as ready for review June 12, 2026 06:04
@zkoppert zkoppert requested a review from jmeridth as a code owner June 12, 2026 06:04
Copilot AI review requested due to automatic review settings June 12, 2026 06:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR strengthens the repo’s quality gate by raising unit test coverage to 100% and enforcing that threshold in CI, while explicitly excluding two unreachable defensive branches via # pragma: no cover.

Changes:

  • Add a new test_coverage_additions.py test module with targeted unit tests to cover previously missed branches across multiple modules.
  • Mark two confirmed-unreachable branches as excluded from coverage with explanatory comments (most_active_mentors.py, markdown_writer.py).
  • Increase the pytest coverage failure threshold from 80% to 100% in the Makefile.
Show a summary per file
File Description
test_coverage_additions.py Adds targeted unit tests to close remaining coverage gaps and reach 100%.
most_active_mentors.py Excludes a dead discussion-counting branch from coverage and documents why it’s unreachable.
markdown_writer.py Excludes an unreachable defensive else branch in group_issues from coverage with rationale.
Makefile Raises --cov-fail-under to 100 to enforce coverage in CI.

Copilot's findings

  • Files reviewed: 4/4 changed files
  • Comments generated: 1

Comment thread test_coverage_additions.py Outdated

@jmeridth jmeridth left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_coverage_additions.py?

I moved the tests that previously lived in test_coverage_additions.py
into the per-module test files (test_config.py, test_labels.py, etc.)
that match the source modules they exercise. This matches the existing
test_<module>.py naming convention in the repo so future maintainers
can find coverage for a given module without grepping a catch-all file.

I also dropped a duplicate test_get_owners_and_repositories_handles_user_prefix
test in test_search.py that exactly matched the existing
test_get_owners_and_repositories_with_user test, and kept the
owner: prefix variant which was not previously covered.

All 191 tests still pass with 100% coverage on every source module.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Zack Koppert <zkoppert@github.com>
zkoppert added a commit to zkoppert/dotfiles that referenced this pull request Jun 12, 2026
…module

I hit a quality issue in github-community-projects/issue-metrics#775 where
I (with AI assistance) added a 945-line test_coverage_additions.py file
that bundled 36 tests across 11 source modules in a single catch-all
test file. That breaks the source-to-test mapping a maintainer relies on
to find the tests for a given module.

I added an explicit rule under Code Style & Languages forbidding
catch-all aggregator test file names (test_coverage_additions.py,
test_extra.py, test_misc.py, test_new_stuff.py, ...) and requiring new
tests to land in the existing test_<module>.py file for the module
they exercise. I also tightened the OSS Actions Project Structure
bullet to reinforce the same rule.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Zack Koppert <zkoppert@github.com>
@zkoppert zkoppert requested a review from Copilot June 12, 2026 15:38
@zkoppert

Copy link
Copy Markdown
Collaborator Author

test_coverage_additions.py?

Wow that was lazy! making a rule to make sure I don't do that again. Thanks for flagging.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 15/15 changed files
  • Comments generated: 4

Comment thread markdown_writer.py
Comment thread most_active_mentors.py
Comment thread test_search.py
Comment thread test_time_to_ready_for_review.py
@zkoppert zkoppert merged commit 2140cf1 into main Jun 12, 2026
42 checks passed
@zkoppert zkoppert deleted the zkoppert/raise-coverage-to-100 branch June 12, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants