I've a function (myfunc), with a validation input a and and c credentials that will setup a service to call func_z.
For some validation input, func_z will throw an error, and in other cases, it'll return some dictionary of values. And I've an outer_func that modifies the output of func_z.
I've tried to mock the func_z as such:
class XError(Excception):
pass
def myfunc(a, b, c):
x = c.setup_client('x')
try:
x.func_z(a) # Check if x.func_z(a) works proper
except:
raise XError
return b**2
def outer_func(a, b, c):
return myfunc(a, b, c) + 1
When testing the function, I had to mock the c credentials. So I tried to test with:
import pytest
from unittest.mock import MagicMock
test_data = ( (('fr', 5), 26), ('de', 7, 50), (('zh', 5), XError) )
SIDE_EFFECTS = {'fr': {'status': 'okay'}, 'de': {'status': 'okay'}, 'zh': XError}
@pytest.mark.parametrize("a, b", test_data)
def mytest(a, b, expected):
mock_creds = MagicMock()
mock_service = MagicMock()
mock_creds.setup_client.return_value = mock_service
mock_service.func_z.return_value = SIDE_EFFECTS[a]
assert outer_func(a, b, mock_creds) == expected
Somehow the XError didn't get raised in the pytest and the output returns 26 for ('zh', 5) inputs instead of XError.
But it seems like I'm not mocking anything.
Did I use the return value in the mock objects wrongly?
Is it possible to allow and check for raised error or outputs with mock objects in pytest?
There are two issues with the test in question.
Returning an exception in mock:
is effectively a
Surely this is not what you want. Instead, you want
func_zmock to raise an error; for that, you need to useside_effect:Asserting an exception is returned from tested function: the
outer_funcdoesn't return an exception, but raises it, sowill fail for
(('zh', 5), XError)parameter asouter_funcwill not return.Instead, write two separate tests since you have two different paths the code can take in
myfunc; thetest_happycovers the path with no exception and the path with error raising is covered bytest_xerror. The code common to both tests (assembling themock_service) is moved out to a fixture.Notice how
pytest.raisescontext is used for testing whetherXErroris raised in the last test. If you want to test exception details, you can store the raised exception and inspect it after thewithblock: