pythonpytest

pytest.skip for a specific exception


I have some test codes to check contents of target file like :

sc = samplechecker(json_root, 'target_file_to_check', {params})
result = sc.run()
res = sc.getId()
taskIds.append(res['data']['Id'])
assert result

And want to skip test if target file is not exist, so modified the code :

try :
    sc = samplechecker(json_root, 'target_file_to_check', {params})
except FileNotFoundError as exc:
    pytest.skip(f"!!! Target file {exc.filename} not found !!!")

result = sc.run()
res = sc.getId()
taskIds.append(res['data']['Id'])
assert result

This works fine for this one case, but I have several similar test modules so would like to apply this to all other cases as well. So tried to add pytest_exception_interact in conftest.py :

in conftest.py :

import pytest

@pytest.hookimpl()
def pytest_exception_interact(node, call, report):
    excinfo = call.excinfo
    excvalue = excinfo.value

    if excinfo.type == FileNotFoundError:
        pytest.skip(f"!!! Target file {excvalue.filename} not found !!!")

But it doesn't work the way I want. Just failed with many of internal error.

...
INTERNALERROR>   File "/home/jyoun/work/venv_xdr-ac/lib/python3.7/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/home/jyoun/work/venv_xdr-ac/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/home/jyoun/work/venv_xdr-ac/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/jyoun/work/venv_xdr-ac/git/SOC-SampleCode/api_reference/test/conftest.py", line 26, in pytest_exception_interact
INTERNALERROR>     pytest.skip(f"!!! Target file {excvalue.filename} not found !!!")
INTERNALERROR>   File "/home/jyoun/work/venv_xdr-ac/lib/python3.7/site-packages/_pytest/outcomes.py", line 112, in skip
INTERNALERROR>     raise Skipped(msg=msg, allow_module_level=allow_module_level)
INTERNALERROR> Skipped: !!! Target file ../sample/targetfile1 not found !!!

How can I reach for the target I want?


Solution

  • The reason you see this INTERNAL_ERROR is because you are raising an exception inside the hook implementation which is a tiny plugin for pytest.

    In other words, you implemented a small plugin to check if a test failed due to a given exception, if that's true, you raise an exception. Instead you should look on how to set that test (I think it is represented as the node here) to skipped and add the skip description at proper place.

    If this is something you would use in many other tests, I would advise you to invest some time to do that.

    On the other hand, if it is sporadically used and you want to see it closer to you test, you can implement a function decorator to capture the exception and raise the skip exception during the test run time.

    Example:

    def skip_on(exception, reason="Default reason"):
        # Func below is the real decorator and will receive the test function as param
        def decorator_func(f):
            @wraps(f)
            def wrapper(*args, **kwargs):
                try:
                    # Try to run the test
                    return f(*args, **kwargs)
                except exception:
                    # If exception of given type happens
                    # just swallow it and raise pytest.Skip with given reason
                    pytest.skip(reason)
    
            return wrapper
    
        return decorator_func
    

    Then decorate your test method like this:

    @skip_on(FileNotFoundError, reason="A good reason to skip")
    def test_something():
        ...
        sc = samplechecker(json_root, 'target_file_to_check', {params})
        result = sc.run()
        res = sc.getId()
        taskIds.append(res['data']['Id'])
        assert result
        ...