Skip to main content

assert-pytest-test-can-fail

Assert that every pytest test is able to fail.

Why Must a Test Be Able to Fail?

A test earns its place by being able to fail. A test whose assertion is satisfied on every path it can reach runs, costs what it costs, and reports green for the whole life of the thing it claims to watch. Coverage counts it. The suite counts it. The only way anybody finds out is by reading it.

One shape produces this reliably. A test sets a flag to False, asks a remote service about a resource, sets the flag to True when the call succeeds, and sets the same flag to True again in the handler for the error that means the resource is absent. Every other error is re-raised. Then it asserts the flag. Every path that reaches the assertion has set it to True, so the assertion is decoration, and a genuinely missing resource is reported as present.

Mutation testing answers this question in general and answers it better, by mutating the code under test and seeing whether a test dies. It cannot answer it for a test with no code under test — one that asserts about a deployed resource through a client library — and it costs a suite run per mutant. This tool asks a narrower question that a parse can settle.

Installation

pip install assert-pytest-test-can-fail

Usage

Command Line

# Scan specific files
assert-pytest-test-can-fail test_example.py

# Scan directories recursively
assert-pytest-test-can-fail test/

# Use glob patterns
assert-pytest-test-can-fail "test/**/test_*.py"

# Exclude patterns
assert-pytest-test-can-fail test/ --exclude "**/conftest.py"

# Verbose output
assert-pytest-test-can-fail test/ --verbose

# Fail fast (exit on first finding)
assert-pytest-test-can-fail test/ --fail-fast

# Warn only (always exit 0)
assert-pytest-test-can-fail test/ --warn-only

GitHub Actions

- uses: 10U-Labs/assert-pytest-test-can-fail@latest
  with:
    files: "test/"
    verbose: "true"

As a Python Module

python -m assert_pytest_test_can_fail test/

Output Format

Default output shows one finding per line:

path/to/test_file.py:23:test_bucket_exists: every path to the assert sets the flag, so the test cannot fail

Format: file_path:line_number:function_name, followed by the reason. The line number is the assert statement.

Exit Codes

  • 0: No findings (or --warn-only specified)
  • 1: Findings detected
  • 2: Error (missing files, syntax errors, etc.)

What Is Reported

A function whose name begins with test is reported when all of these are true:

  • it contains a try statement with at least one except handler
  • the statement that ends the try body — or the else clause, when there is one — assigns True to a bare name
  • every handler on that try is closed: it ends in raise, or it ends assigning True to that same name, or it ends in an if/else whose two branches each do one of those
  • an assert on that bare name follows the whole try statement

The last one matters. An assertion sitting inside the try, or above it, is asking a different question, and is left alone.

Each reported function is reported once, at the first assertion that qualifies.

What Is Never Reported

The shape alone is not the defect, and a rule that says otherwise is a rule nobody keeps. A permission check written this way is correct: it asks whether the credentials may inspect a resource, a 404 answers yes, and any error code the handler does not name leaves the flag False, so the assertion fails.

def test_can_describe_bucket():
    has_permission = False
    try:
        client.head_bucket(Bucket=name)
        has_permission = True
    except ClientError as error:
        code = error.response["Error"]["Code"]
        if code == "403":
            pytest.fail("No permission to inspect the bucket")
        if code == "404":
            has_permission = True
    assert has_permission

That handler ends in an if with no else, so it can complete with the flag still False. It is not reported. Neither is a handler that ends in pass, nor a pytest.fail that leaves other codes falling through — only raise and an assignment on every branch close a handler.

Also never reported:

  • a try with no except handler at all, such as try/finally
  • a success path that computes the flag rather than asserting it, such as exists = client.bucket_exists(name)
  • a chained assignment, exists = asked = True, or an attribute target, record.exists = True
  • an assertion on anything but a bare name, such as assert count == 1
  • a try inside a nested function, a lambda or a class the test defines: the tool does not descend into a scope the test opens
  • a function whose name does not begin with test

Only files pytest would collect are scanned: test_*.py and *_test.py.

Options

Option Description
--exclude PATTERNS Glob patterns to exclude (comma-separated)
--quiet Suppress all output (exit code only)
--count Output only the number of findings
--verbose Show detailed processing information
--fail-fast Exit after first finding
--warn-only Always exit 0, even with findings

License

Apache 2.0 - See LICENSE.txt

Metadata

Release files for assert-pytest-test-can-fail 20260908004717

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for assert-pytest-test-can-fail 20260908004717
File Size Uploaded Provenance
assert_pytest_test_can_fail-20260908004717.tar.gz 27.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for assert-pytest-test-can-fail 20260908004717
File Interpreter ABI Platform
assert_pytest_test_can_fail-20260908004717-py3-none-any.whl Python 3 none any Details

Total release size: 39.9 kB

Release files / assert_pytest_test_can_fail-20260908004717.tar.gz

Download URL assert_pytest_test_can_fail-20260908004717.tar.gz
Size 27.4 kB
Tags Source
SHA-256 checksum
How to use checksums
650f3b7c6c8601354a48b722632787c830eea380b4fbde83ee4f690a511b9969
BLAKE2b-256 checksum
How to use checksums
2bc73ac26b9c367ae2e05c653c7ebf51982103c05f0e1fd661ee56dce14f7e77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.

Transparency log

Release files / assert_pytest_test_can_fail-20260908004717-py3-none-any.whl

Download URL assert_pytest_test_can_fail-20260908004717-py3-none-any.whl
Size 12.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bf6e398819373dcefa4cecd864347c10d126809dc371182de21d29ffdda93715
BLAKE2b-256 checksum
How to use checksums
2cfc3c7676f1e2fabfebec03c622933f30a8dea35b83053d3c6f8c3dfb79a869
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.

Transparency log

Security for assert-pytest-test-can-fail 20260908004717

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for assert_pytest_test_can_fail-20260908004717.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page