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_z
mock to raise an error; for that, you need to useside_effect
:Asserting an exception is returned from tested function: the
outer_func
doesn't return an exception, but raises it, sowill fail for
(('zh', 5), XError)
parameter asouter_func
will not return.Instead, write two separate tests since you have two different paths the code can take in
myfunc
; thetest_happy
covers 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.raises
context is used for testing whetherXError
is raised in the last test. If you want to test exception details, you can store the raised exception and inspect it after thewith
block: