Python unit test mock, get mocked function's input arguments
Question:
I want a unit test to assert that a variable action
within a function is getting set to its expected value, the only time this variable is used is when it is passed in a call to a library.
Class Monolith(object):
def foo(self, raw_event):
action = # ... Parse Event
# Middle of function
lib.event.Event(METADATA, action)
# Continue on to use the build event.
My thought was that I could mock lib.event.Event
, and get its input arguments and assert they are of specific value.
>Is this not how mocks work? The mock documentation frustrates me with its inconsistency, half-examples, and plethora of examples that are not related to what I want to do.
Answers:
You could use patch decorator and then call assert_called_with
to that mocked object like this:
If you have this structure:
example.py
tests.py
lib/__init__.py
lib/event.py
And the content of example.py
is:
import lib
METADATA = 'metadata_example'
class Monolith(object):
def foo(self, raw_event):
action = 'action_example' # ... Parse Event
# Middle of function
lib.event.Event(METADATA, action)
# Continue on to use the build event.
And the content of lib/event.py
is:
class Event(object):
def __init__(self, metadata, action):
pass
The code of tests.py
should be like:
import mock
import unittest
from lib.event import Event
from example import Monolith
class TestExample(unittest.TestCase):
@mock.patch('lib.event.Event')
def test_example1(self, event_mocked):
# Setup
m = Monolith()
# Exercise
m.foo('raw_event')
# Verify
event_mocked.assert_called_with('metadata_example', 'action_example')
If you want to access arguments directly, how about this? A little redundant though…
See https://docs.python.org/3.6/library/unittest.mock.html#unittest.mock.call.call_list
import mock
import unittest
from lib.event import Event
from example import Monolith
class TestExample(unittest.TestCase):
@mock.patch('lib.event.Event')
def test_example1(self, event_mocked):
# Setup
m = Monolith()
# Exercise
m.foo('raw_event')
# Verify
name, args, kwargs = m.mock_calls[0]
self.assertEquals(name, "foo")
self.assertEquals(args, ['metadata_example', 'action_example'])
self.assertEquals(kwargs, {})
You can use call_args
or call_args_list
as well.
A quick example would look like:
import mock
import unittest
class TestExample(unittest.TestCase):
@mock.patch('lib.event.Event')
def test_example1(self, event_mocked):
args, kwargs = event_mocked.call_args
args = event_mocked.call_args.args # alternatively
self.assertEqual(args, ['metadata_example', 'action_example'])
I just quickly written this example for somebody who might need it – I have not actually tested this so there might be minor bugs.
I want a unit test to assert that a variable action
within a function is getting set to its expected value, the only time this variable is used is when it is passed in a call to a library.
Class Monolith(object):
def foo(self, raw_event):
action = # ... Parse Event
# Middle of function
lib.event.Event(METADATA, action)
# Continue on to use the build event.
My thought was that I could mock lib.event.Event
, and get its input arguments and assert they are of specific value.
>Is this not how mocks work? The mock documentation frustrates me with its inconsistency, half-examples, and plethora of examples that are not related to what I want to do.
You could use patch decorator and then call assert_called_with
to that mocked object like this:
If you have this structure:
example.py
tests.py
lib/__init__.py
lib/event.py
And the content of example.py
is:
import lib
METADATA = 'metadata_example'
class Monolith(object):
def foo(self, raw_event):
action = 'action_example' # ... Parse Event
# Middle of function
lib.event.Event(METADATA, action)
# Continue on to use the build event.
And the content of lib/event.py
is:
class Event(object):
def __init__(self, metadata, action):
pass
The code of tests.py
should be like:
import mock
import unittest
from lib.event import Event
from example import Monolith
class TestExample(unittest.TestCase):
@mock.patch('lib.event.Event')
def test_example1(self, event_mocked):
# Setup
m = Monolith()
# Exercise
m.foo('raw_event')
# Verify
event_mocked.assert_called_with('metadata_example', 'action_example')
If you want to access arguments directly, how about this? A little redundant though…
See https://docs.python.org/3.6/library/unittest.mock.html#unittest.mock.call.call_list
import mock
import unittest
from lib.event import Event
from example import Monolith
class TestExample(unittest.TestCase):
@mock.patch('lib.event.Event')
def test_example1(self, event_mocked):
# Setup
m = Monolith()
# Exercise
m.foo('raw_event')
# Verify
name, args, kwargs = m.mock_calls[0]
self.assertEquals(name, "foo")
self.assertEquals(args, ['metadata_example', 'action_example'])
self.assertEquals(kwargs, {})
You can use call_args
or call_args_list
as well.
A quick example would look like:
import mock
import unittest
class TestExample(unittest.TestCase):
@mock.patch('lib.event.Event')
def test_example1(self, event_mocked):
args, kwargs = event_mocked.call_args
args = event_mocked.call_args.args # alternatively
self.assertEqual(args, ['metadata_example', 'action_example'])
I just quickly written this example for somebody who might need it – I have not actually tested this so there might be minor bugs.