Skip to content

python: warn when an abstract test class swallows its tests - #15082

Draft
RonnyPfannschmidt wants to merge 1 commit into
pytest-dev:mainfrom
RonnyPfannschmidt:abstract-test-class-warning
Draft

RonnyPfannschmidt wants to merge 1 commit into
pytest-dev:mainfrom
RonnyPfannschmidt:abstract-test-class-warning

Conversation

@RonnyPfannschmidt

Copy link
Copy Markdown
Member

Written by Claude Opus 5 via Claude Code for the pytest maintainers; I prompted it, it did the work, I read it.

Draft, for the design question in #13546 rather than for merge as it stands.

Abstract classes have not been collected since #12318, which fixed the Can't instantiate abstract class regression of #12275. That is right for a base class written to be subclassed, but a leaf class that merely forgot to implement a blank looks exactly the same, so its tests stop running and nothing says so. Reported four times: #13546, #14003, #15080, #15081.

This warns when an abstract class matches the test-class naming conventions (or is a unittest.TestCase subclass), carries tests, declares no abstract method of its own, and does not set __test__ in its own body. Declaring a blank is read as meaning to be a base class, so the template-base pattern stays silent and no new API is needed. The __test__ opt-out is read off the class rather than through inheritance, because an inherited __test__ would silence every subclass too.

The unittest hook warns for itself and returns a result rather than None, both because unittest classes are collected regardless of python_classes — aiohttp's InvalidTestCase in #13546 would otherwise be missed — and to keep the python plugin from warning about the same class a second time.

The open question, and why this is a draft: TestPartial in test_abstract_class_is_not_collected is a deliberate intermediate layer that implements one blank and adds none, so it now warns. This PR makes that test ignore the warning rather than paper over it. A deliberate middle layer and a leaf that went dark are textually identical; suppressing the false positive also suppresses the "base class grew a new abstract method" case that motivates the whole change. __test__ = False in the body is the escape hatch. See #13546 for the reasoning.

Not included: @abstractmethod on a class without ABCMeta is collected, called, and passes vacuously. Separate failure mode, separate issue.

🤖 Generated with Claude Code

Abstract classes have not been collected since pytest-dev#12318, which fixed the
`Can't instantiate abstract class` regression of pytest-dev#12275. That is right for a
base class written to be subclassed, but a leaf class that merely forgot to
implement a blank looks exactly the same, so its tests stop running and
nothing says so -- reported four times now, most recently in pytest-dev#15080/pytest-dev#15081.

Warn when an abstract class matches the test class naming conventions, carries
tests, declares no abstract method of its own, and does not set `__test__` in
its own body. Declaring a blank is read as meaning to be a base class; the
`__test__` opt-out is read off the class rather than through inheritance,
because an inherited `__test__` would silence every subclass too.

The unittest hook warns for itself and returns a result rather than None, both
because unittest classes are collected regardless of `python_classes` and to
keep the python plugin from warning about them a second time.

Co-Authored-By: Claude Opus 5 (1M context) via Claude Code <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant