Библиотека макетов Python: есть ли способ получить соответствующие возвращаемые значения от вызовов магического макета?

При написании тестов Python с mock библиотека, я часто получаю "с какими аргументами вызывается метод", как это,

from __future__ import print_function
import mock

m = mock.MagicMock(side_effect=lambda x: x * x)
m(4)
print("m called with: ", m.call_args_list)

(это напечатает m called with: [call(4)]). Вопрос: есть ли способ получить возвращаемое значение (в этом случае 16)?

Детали: в моем конкретном сценарии я хочу использовать side_effect для возврата субмодельного объекта: важно исследовать этот объект, чтобы увидеть, что к нему вызывается. Например, "реальный код" (не тестовый код) может написать

myobj = m(4)
myobj.foo()

С помощью side_effect кажется удобным способом вернуть новые субмодельные объекты, но также держать call_args_list, Тем не менее, это не похоже на MagicMock хранит возвращаемые значения из side_effect функция... я не прав?

4 ответа

А как насчет параметра обертки?

class MyClass:
    def foo(self, x):
        return(x * x)

тогда вы можете подтвердить такой вызов:

my_obj = MyClass()
with patch.object(MyClass, 'foo', wraps=MyClass().foo) as mocked_foo:
    my_result = my_obj.foo(4)
    mocked_foo.assert_called_with(4)    

а my_result будет содержать фактический результат вызова foo()

Это не то, для чего предназначены издевательства, если вы спросите меня. Если вы хотите установить возвращаемое значение, вам следует вызвать функцию напрямую. Если вам нужно перейти через обручи, чтобы зарегистрировать то, что возвращает функция, ваш дизайн, скорее всего, имеет недостатки.

Если, например, у вас есть внутренняя функция, вам не следует проверять внутреннюю функцию. Если вы хотите проверить внутреннюю функцию, сделайте ее общедоступной.

Итак, вместо этого:

def spam(input):
    def eggs(nested):
        return nested*2
    input = eggs(nested)
    return eggs(input)

Сделай это:

def eggs(nested):
    return nested*2

def spam(input):
    input = eggs(nested)
    return eggs(input)

Вам не нужен side_effectТо есть то, что издеваются уже без него, они возвращают другие издевательства.

Вы делаете на них утверждения, делая mymock.return_value.assert_called_once_with(4)

Если бы вы это сделали, вы бы просто вернули издевательство, на которое у вас была ссылка в другом месте, из side_effect,

Использование return_value,

Например,

import unittest

import mock

def foo(m):
    myobj = m(4)
    myobj.foo()

import unittest

class TestFoo(unittest.TestCase):
    def test_foo(self):
        m2 = mock.MagicMock()
        m = mock.MagicMock(return_value=m2)

        foo(m)

        m.assert_called_once_with(4)
        m2.foo.assert_called_once_with()

if __name__ == '__main__':
    unittest.main()

У вас есть объект call(). Вы хотите получить аргументы ВНУТРИ объекта вызова. То есть, если вы получаете

call_args_list[0] == call(3, 5)

Вы хотите 3 и 5. Объект call() может быть проиндексирован - сначала обратитесь к элементу 0, который является списком фактических аргументов. Затем вы хотите 3, который находится внутри него как 0-й элемент.

Получите это с:

cargs = call_args_list[0]
assert cargs[0][0] == 3

>>> mockObjThing.someFunc.call_args_list[0]
call('argOne', 'argTwo') 
>>> # DAGNABBIT I want argOne!!!
>>> cargs = mockObjThing.someFunc.call_args_list[0]
>>> cargs
call('argOne', 'argTwo') 
>>> cargs[0]
('argOne', 'argTwo')
>>> cargs[0][0]
'argOne'
Другие вопросы по тегам