Delayed/Soft Assertions for Python
delayed-assert is a Python library that provides delayed or soft assertions, allowing test execution to continue even after an `expect()` call fails. All accumulated failures are then reported at a designated point using `assert_expectations()` or implicitly with a decorator/context manager. It is framework-agnostic and currently at version 0.4.2, with a moderate release cadence focusing on usability and feature enhancements like improved test case identification and output control.
Common errors
-
ImportError: No module named 'delayed_assert'
cause The `delayed-assert` package is either not installed, or there's an issue with the Python environment's path, or an incorrect import statement (e.g., `import delayed_assert.delayed_assert`).fixEnsure the package is installed using `pip install delayed-assert`. Verify the import statement is `from delayed_assert import expect, assert_expectations` (or other specific symbols). -
AssertionError: Some expectations failed.
cause This error is the intended behavior of `assert_expectations()` (or `@assert_all()`) when one or more `expect()` calls have evaluated to `False`.fixReview the details printed with the `AssertionError` to identify which `expect()` calls failed. These details will include the expression, message, and location of the failure. This indicates a test failure, not a library issue. -
SyntaxError: invalid syntax (cannot use 'assert' statement inside a lambda)
cause Attempting to use Python's `assert` statement directly within a lambda function passed to `expect()`.fixReformulate the condition as a boolean expression (e.g., `expect(x == y)`) or, if integrating with `unittest` assertions, pass the `unittest` assertion method directly to the lambda (e.g., `expect(lambda: self.assertEqual(x, y))`). -
Error: expect() must be called from a method named 'test_*' or marked with '@test_case' if caller verification is enabled.
cause This occurs when `expect()` is called from a function whose name does not start with `test_`, and caller verification (default enabled in >=0.4.1) is active.fixRename your function to start with `test_`, apply the `@test_case` decorator to the function, or disable caller verification as described in the warnings section (e.g., `DELAYED_ASSERT_CHECK_CALLER=0` or `set_check_caller(False)`).
Warnings
- gotcha By default, `expect()` verifies that it is called from a method named `test_something`. If you use `expect()` in helper methods or functions not prefixed with `test_`, it might raise an error.
- gotcha When using `expect()` with lambda expressions, `assert` statements are not valid within a lambda. For example, `expect(lambda: assert 1 == 1)` will result in a `SyntaxError`.
- gotcha If you are not using the `@assert_all()` decorator or `with assert_all():` context manager, you must explicitly call `assert_expectations()` at the end of your test case to report any collected failures.
- gotcha Colorized output for failure reports is enabled by default. This might introduce unwanted ANSI escape codes into logs or environments that don't support color output (e.g., some CI/CD pipelines).
Install
-
pip install delayed-assert
Imports
- expect
from delayed_assert import expect
- assert_expectations
from delayed_assert import assert_expectations
- test_case
from delayed_assert import test_case
- assert_all
from delayed_assert import assert_all
- set_check_caller
from delayed_assert import set_check_caller
- set_color_enabled
from delayed_assert import set_color_enabled
Quickstart
from delayed_assert import expect, assert_expectations, test_case, assert_all
@test_case
def my_test_scenario():
print("\n--- Running my_test_scenario ---")
expect(1 == 1, "Assertion 1 (should pass)")
expect(1 == 2, "Assertion 2 (should fail)")
expect(3 > 2, "Assertion 3 (should pass)")
expect("hello" == "world", "Assertion 4 (should fail)")
print("Continuing after failed expectations...")
assert_expectations()
@assert_all()
def another_test_case():
print("\n--- Running another_test_case (with decorator) ---")
expect(True, "True is True")
expect(False, "False is not True")
# No need to call assert_expectations() explicitly here
if __name__ == "__main__":
try:
my_test_scenario()
except AssertionError as e:
print(f"Caught expected AssertionError for my_test_scenario:\n{e}")
try:
another_test_case()
except AssertionError as e:
print(f"Caught expected AssertionError for another_test_case:\n{e}")