Atenea_v10
Atenea_v10

Reputation: 107

How to dynamically mock the result of a python function inside a for loop?

I'm trying to implement some unittests to validate a method that contains a for loop. This method receives a list of items and for each one of them it executes a function foo() with the item as a parameter.

Does anyone know how can I mock the foo() function to dynamically provide the mocked returned value depending on the element provided as input?

The methods:

def foo(i):
    if i == 'this':
        return 'a'
    else:
        return 'b'

def bar(items):
    results = []
    for item in items:
        results.append(foo(item))
    return results

The unittest:

from unittest import TestCase
from mock import patch

class TestCaseBar(TestCase):

    @patch('my_module.foo')
    def test_bar(self, mock_foo):
        mock_foo.return_value = 'dummy'  # I would like to dinamically mock this.
        items = ['this', 'that']
        result = bar(items)
        self.assertEqual(result, ['a', 'b'])
        self.assertTrue(mock_foo.call_count, 2)
    

Thanks in advance for your answers.

Upvotes: 2

Views: 6068

Answers (1)

Lin Du
Lin Du

Reputation: 102267

You could use assign a function to the side_effect property for a mock object. Then, you can implement the mocked details for it.

A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values.

E.g.

my_module_64443736.py:

def foo(i):
    if i == 'this':
        return 'a'
    else:
        return 'b'


def bar(items):
    results = []
    for item in items:
        results.append(foo(item))
    return results

test_my_module_64443736.py:

from unittest import TestCase, main
from unittest.mock import patch
from my_module_64443736 import bar


class TestCaseBar(TestCase):

    @patch('my_module_64443736.foo')
    def test_bar(self, mock_foo):
        def dynamicMock(i):
            if i == 'this':
                return 'teresa teng'
            else:
                return 'best singer'
        mock_foo.side_effect = dynamicMock
        items = ['this', 'that']
        result = bar(items)
        self.assertEqual(result, ['teresa teng', 'best singer'])
        self.assertTrue(mock_foo.call_count, 2)


if __name__ == '__main__':
    main()

unit test result:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
Name                                                    Stmts   Miss  Cover   Missing
-------------------------------------------------------------------------------------
src/stackoverflow/64443736/my_module_64443736.py            9      3    67%   2-5
src/stackoverflow/64443736/test_my_module_64443736.py      16      0   100%
-------------------------------------------------------------------------------------
TOTAL                                                      25      3    88%

Upvotes: 5

Related Questions