This rule raises an issue when assertion statements, assertion methods, or fluent assertions are placed within a try block that catches AssertionError exceptions without properly handling or re-raising them.

Why is this an issue?

Assertions in Python raise an AssertionError when they fail. This includes built-in assert statements, unittest assertion helpers such as assertEqual, and fluent assertions from libraries such as assertpy. This is the mechanism testing frameworks use to detect test failures.

When you place assertions within a try-except block that catches AssertionError (or its parent class Exception), and you do not re-raise the exception or validate its properties, you create a silent failure scenario. The assertion can fail, but the exception gets swallowed by the except block, causing the test to pass when it should have failed.

This defeats the entire purpose of writing assertions in tests. The test appears to pass, giving false confidence that the code works correctly, when in reality the assertion failed and detected a problem.

The root cause of this anti-pattern is usually a misunderstanding of exception handling in tests. Developers might add try-except blocks around assertions thinking they need to "handle" exceptions, but assertions are meant to propagate upward to the test framework.

This issue commonly occurs when:

What is the potential impact?

When assertions are silently caught and ignored, tests provide false confidence in the codebase. Code that should fail tests will appear to pass, allowing bugs to reach production.

This can lead to:

How to fix it in unittest

Code examples

Noncompliant code example

The assertion (self.fail(…​)) raises an AssertionError, which is immediately caught by the surrounding except AssertionError block and silently discarded. As a result, the test can never fail, even when do_something() does not behave as expected.

import unittest

class MyTest(unittest.TestCase):
    def test_should_raise_error(self):
        try:
            self.do_something()
            self.fail("Expected an AssertionError!")  # Noncompliant
        except AssertionError:
            pass

    def do_something(self):
        raise AssertionError("Something went wrong")

This variation has the same problem: the AssertionError is caught locally and ignored. The test appears to check the exception details, but it never validates anything about the caught error.

import unittest

class MyTest(unittest.TestCase):
    def test_error_message(self):
        try:
            self.do_something()
            self.fail("Expected an AssertionError!")  # Noncompliant
        except AssertionError:
            pass  # Exception caught but not validated

    def do_something(self):
        raise AssertionError("Something went wrong")

Compliant solution

Use the proper assertion context managers provided by the testing framework. The assertRaises context manager is designed specifically for testing that exceptions are raised, without accidentally catching assertion failures.

import unittest

class MyTest(unittest.TestCase):
    def test_should_raise_error(self):
        with self.assertRaises(AssertionError):
            self.do_something()

    def do_something(self):
        raise AssertionError("Something went wrong")

If you need to verify specific properties of the exception, you can access the exception object through the context manager and make assertions about it after the context exits. This ensures the exception is properly raised while still allowing you to validate its details.

import unittest

class MyTest(unittest.TestCase):
    def test_error_message(self):
        with self.assertRaises(AssertionError) as context:
            self.do_something()

        self.assertEqual(str(context.exception), "Something went wrong")

    def do_something(self):
        raise AssertionError("Something went wrong")

How to fix it in pytest

Code examples

Noncompliant code example

The assert False statement raises an AssertionError, which is then swallowed by the surrounding except AssertionError block. Because of that, the test can never fail when do_something() does not raise the expected error.

import pytest

def test_should_raise_error():
    try:
        do_something()
        assert False, "Expected an AssertionError!"  # Noncompliant
    except AssertionError:
        pass

def do_something():
    raise AssertionError("Something went wrong")

Here too, the caught AssertionError is never validated or re-raised. The test silently succeeds instead of checking that the expected failure really happened.

import pytest

def test_error_details():
    try:
        do_something()
        assert False, "Expected an AssertionError!"  # Noncompliant
    except AssertionError:
        pass  # Exception details not validated

def do_something():
    raise AssertionError("Something went wrong")

Compliant solution

When using pytest, use the pytest.raises context manager to properly test for exceptions. This ensures that assertion failures are not accidentally caught.

import pytest

def test_should_raise_error():
    with pytest.raises(AssertionError):
        do_something()

def do_something():
    raise AssertionError("Something went wrong")

To validate specific exception properties with pytest, access the exception info from the context manager. You can then make assertions about the exception message or other attributes.

import pytest

def test_error_details():
    with pytest.raises(AssertionError) as exc_info:
        do_something()

    assert str(exc_info.value) == "Something went wrong"

def do_something():
    raise AssertionError("Something went wrong")

How to fix it in assertpy

Code examples

Noncompliant code example

With assertpy, fluent assertions still raise AssertionError. Catching that exception in the surrounding try-except block can hide a failing test.

from assertpy import assert_that

def test_result():
    try:
        result = get_result()
        assert_that(result).is_equal_to("expected")  # Noncompliant
    except AssertionError:
        pass

Compliant solution

Keep the assertpy assertion outside the try-except block so test failures are reported normally.

from assertpy import assert_that

def test_result():
    result = get_result()
    assert_that(result).is_equal_to("expected")

Resources

Documentation