pytest Exceptions - Part II
pytest Exceptions (2 Part Series)
We’ve already seen how to test exceptions with pytest in part I. However what’s going to happen if we didn’t fully implement our method yet or don’t want to test on different os platforms, language versions etc.?
For these kind of tests we can use skip
and xfail
:
- A skip means that you expect your test to pass only if some conditions are met,
- An xfail means that you expect a test to fail for some reason.
Let’s assume we got a dummy method which calls a third party API;
from typing import Optional
import requests
from .exceptions import ParametersError, PaymentGatewayError, UserPermissionError
def incomplete_business_logic_method(*args, **kwargs) -> Optional[str]:
response = None
try:
response = expensive_calculation_method(*args, **kwargs)
except APIGatewayError as exc:
raise APIGatewayError() from exc
except requests.exceptions.HTTPError as exc:
if exc.response.status_code == 400:
error = exc.response.json()
code = error['code']
message = error['message']
if exc.code == 2001:
raise ParametersError(exc.code, exc.message) from exc
else:
raise UserPermissionError(exc.code, exc.message) from exc
return response
And exceptions module looks like this:
class APIGatewayError(Exception):
pass
class PaymentGatewayError(APIGatewayError):
def __init__(self, code, message):
self.code = code
self.message = message
class ParametersError(PaymentGatewayError):
pass
class UserPermissionError(PaymentGatewayError):
pass
xfail
You can use xfail
marker to indicate that you expect a test to fail:
import pytest
from .exceptions import APIGatewayError
@pytest.mark.xfail(raises=APIGatewayError)
def test_incomplete_business_logic_method(self):
...
return incomplete_business_logic_method(*args, **kwargs)
If a test is only expected to fail under a certain condition — like in skipif
,
you can pass that condition as the first parameter:
import pytest
@pytest.mark.xfail(sys.version_info < (3, 6), reason="requires python3.6 or higher")
def test_incomplete_business_logic_method(self):
...
return incomplete_business_logic_method(*args, **kwargs)
skip
The simplest way to skip a test function is to mark it with the skip
decorator which may be passed an optional reason:
import pytest
@pytest.mark.skip(reason="not implement this yet")
def test_incomplete_business_logic_method(self):
...
return incomplete_business_logic_method(*args, **kwargs)
skipif
If you wish to skip something conditionally then you can use skipif
:
import pytest
@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires python3.6 or higher")
def test_incomplete_business_logic_method(self):
...
return incomplete_business_logic_method(*args, **kwargs)
Addition
You can show extra info on xfailed and skipped tests with -rxs
:
$ pytest -rxs
Get more info on offical doc :skip and xfail.
All done!