pytest icon indicating copy to clipboard operation
pytest copied to clipboard

conditionally rewrite assertions / support assertion descriptions in `pytest_assertion_pass` and `pytest_assertrepr_compare` hooks

Open DetachHead opened this issue 2 years ago • 1 comments

What's the problem this feature will solve?

in my plugin, i want to be able to customize or rewrite assertions based on the second argument to the assert statement:

assert False, "value was false"

Describe the solution you'd like

either of these two solutions:

  1. a hook to determine whether to rewrite an assertion:
    @hookimpl(firstresult=True) # first non-None result means don't rewrite
    def pytest_rewrite_assertion(item: Item, lineno: int, orig: str, description: object):
        ...
    
  2. add a new "description" argument to these existing hooks:
    def pytest_assertion_pass(item: Item, lineno: int, orig: str, expl: str, description: object):
        ...
    
    def pytest_assertrepr_compare(config: Config, op: str, left: object, right: object, description: object):
        ...
    

Additional context

this is mainly for the concept of "user-facing" vs "non-user-facing" assertions

user-facing assertions

a user-facing assertion is written as part of the test (ie. ensuring that the function being tested has the correct value)

def test_get_value():
    assert get_value(1) == 1
non-user-facing assertions

a non-user-facing assertion is used for things like narrowing types, typically in utility functions which have nothing to do with the test itself

def get_value(value: object):
    assert isinstance(value, int)
    ...

def test_get_value():
    assert get_value(1) == 1

my plugin is a robotframework test runner: https://github.com/DetachHead/pytest-robotframework. robotframework assertions are different to pytest assertions, since they use functions (called keywords) like should_be_equal, should_not_be_equal, etc.

we are in the process of converting an existing robotframework codebase to python using this plugin, however since the user-facing assertions were handled by those keywords, there are hundreds of assert statements in the codebase that were written as regular python non-user-facing assert statements and are not meant to be displayed to the user. we want to replace them all with pytest assertions though.

i know you can use register_assert_rewrite to control which modules have their assert statements rewritten, but in many cases there are user-facing and non-user-facing assertions in the same module.

DetachHead avatar Feb 14 '24 03:02 DetachHead

in my plugin i hacked together a new hook that allows me to do this. it lets you pass an options object as the second argument which it then uses to customize how the assertion appears in the log:

assert True, AssertOptions(description="foo", log_pass=False)

would be awesome if something like that was officially supported though

DetachHead avatar Feb 16 '24 23:02 DetachHead