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.

Asked By: ThorSummoner

||

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')
Answered By: gsoriano

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, {})
Answered By: nonki

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.

Answered By: akki
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.