I'm a beginner to python and pytest. I have a function that I'm trying to test for the exceptions part with Pytest:
def read_data(args) -> tuple[Polyline, str]:
parsed_args = input_parsing_1(args)
try:
with open(parsed_args.f) as f_input:
reader = csv.reader(f_input)
polyline = fill_poly_with_data(reader)
except FileNotFoundError as e:
sys.exit('Invalid input file \n')
else:
return (polyline, parsed_args.f)
I want to test if exceptions are risen and if the error message matches the one I put in the code above.
My attempts
@patch('project.open')
def test_read_data_error_SE(mock_open):
mock_open.side_effect = SystemExit
with pytest.raises(SystemExit):
assert read_data(['-f', ''])
@patch('project.open')
def test_read_data_error_FNFE2(mock_open):
mock_open.side_effect = FileNotFoundError
with pytest.raises(SystemExit):
with pytest.raises(FileNotFoundError):
assert read_data(['-f', 'cos'])
The above tests works fine.
I also wish to assert if sys.exit message matches 'Invalid input file \n'
. I've tried:
@patch('project.open')
def test_read_data_error_SE1(mock_open):
mock_open.side_effect = SystemExit
with pytest.raises(SystemExit, match='Invalid input file'):
assert read_data(['-f', ''])
@patch('project.open')
def test_read_data_error_SE2(mock_open):
mock_open.side_effect = SystemExit
with pytest.raises(SystemExit) as e:
assert read_data(['-f', ''])
assert 'Invalid input file' in str(e.value)
but those tests fails:
===================================================== short test summary info ======================================================
FAILED test_project.py::test_read_data_error_SE1 - AssertionError: Regex pattern did not match.
FAILED test_project.py::test_read_data_error_SE2 - AssertionError: assert 'Invalid input file' in ''
I have seen some posts here on stackoverflow, like: Verify the error code or message from SystemExit in pytest
How to properly assert that an exception gets raised in pytest?
Catch SystemExit message with Pytest
but none of them seems to answer my problem.
My questions:
It seems like my tested message 'Invalid input file' is being matched to an empty string ''? Why? How to properly catch and assert the sys.exit('some error message')?
CodePudding user response:
You're seeing an empty string because you're raising SystemExit with no parameters:
@patch('project.open')
def test_read_data_error_SE1(mock_open):
mock_open.side_effect = SystemExit
with pytest.raises(SystemExit, match='Invalid input file'):
assert read_data(['-f', ''])
You've set mock_open.side_effect = SystemExit
, so when you're code calls open()
, it raises SystemExit
with no parameters. If you want to see a message like Invalid input file
, have your code explicitly exit by calling sys.exit('Invalid input file')
.
Your code already does that, but you're pre-empting that behavior by having the call to open
raise SystemExit
instead. You probably want open
to raise FileNotFound
instead:
@patch('project.open')
def test_read_data_error_SE1(mock_open):
mock_open.side_effect = FileNotFound
with pytest.raises(SystemExit, match='Invalid input file'):
assert read_data(['-f', ''])
This will get caught by the except
in read_data
, which will then call sys.exit
.
Here's a complete example (I've included some stub functions here so that I can use your read_data
method largely unmodified):
import csv
import sys
import types
import pytest
from unittest import mock
def fill_poly_with_data(x):
return x
def input_parsing_1(args):
return types.SimpleNamespace(f="testing")
def read_data(args) -> tuple:
parsed_args = input_parsing_1(args)
try:
with open(parsed_args.f) as f_input:
reader = csv.reader(f_input)
polyline = fill_poly_with_data(reader)
except FileNotFoundError:
sys.exit('Invalid input file \n')
else:
return (polyline, parsed_args.f)
@mock.patch('builtins.open')
def test_function_that_exits(mock_open):
mock_open.side_effect = FileNotFoundError
with pytest.raises(SystemExit, match="Invalid input file"):
read_data(['-f', 'cos'])