Mocking python function based on input arguments

2020-02-07 16:20发布

We have been using Mock for python for a while.

Now, we have a situation in which we want to mock a function

def foo(self, my_param):
    #do something here, assign something to my_result
    return my_result

Normally, the way to mock this would be (assuming foo being part of an object)

self.foo = MagicMock(return_value="mocked!")

Even, if i call foo() a couple of times i can use

self.foo = MagicMock(side_effect=["mocked once", "mocked twice!"])

Now, I am facing a situation in which I want to return a fixed value when the input parameter has a particular value. So if let's say "my_param" is equal to "something" then I want to return "my_cool_mock"

This seems to be available on mockito for python

when(dummy).foo("something").thenReturn("my_cool_mock")

I have been searching on how to achieve the same with Mock with no success?

Any ideas?

8条回答
等我变得足够好
2楼-- · 2020-02-07 17:01

You can also use @mock.patch.object:

Let's say a module my_module.py uses pandas to read from a database and we would like to test this module by mocking pd.read_sql_table method (which takes table_name as argument).

What you can do is to create (inside your test) a db_mock method that returns different objects depending on the argument provided:

def db_mock(**kwargs):
    if kwargs['table_name'] == 'table_1':
        # return some DataFrame
    elif kwargs['table_name'] == 'table_2':
        # return some other DataFrame

In your test function you then do:

import my_module as my_module_imported

@mock.patch.object(my_module_imported.pd, "read_sql_table", new_callable=lambda: db_mock)
def test_my_module(mock_read_sql_table):
    # You can now test any methods from `my_module`, e.g. `foo` and any call this 
    # method does to `read_sql_table` will be mocked by `db_mock`, e.g.
    ret = my_module_imported.foo(table_name='table_1')
    # `ret` is some DataFrame returned by `db_mock`
查看更多
对你真心纯属浪费
3楼-- · 2020-02-07 17:02

If side_effect is a function then whatever that function returns is what calls to the mock return. The side_effect function is called with the same arguments as the mock. This allows you to vary the return value of the call dynamically, based on the input:

>>> def side_effect(value):
...     return value + 1
...
>>> m = MagicMock(side_effect=side_effect)
>>> m(1)
2
>>> m(2)
3
>>> m.mock_calls
[call(1), call(2)]

http://www.voidspace.org.uk/python/mock/mock.html#calling

查看更多
登录 后发表回答