Использование python mock patch.object для изменения возвращаемого значения метода, вызванного другим методом
Можно ли смоделировать возвращаемое значение функции, вызываемой внутри другой функции, которую я пытаюсь проверить? Я хотел бы, чтобы mocked-метод (который будет вызываться во многих тестируемых мной методах) возвращал мои указанные переменные при каждом вызове. Например:
class Foo:
def method_1():
results = uses_some_other_method()
def method_n():
results = uses_some_other_method()
В модульном тесте я хотел бы использовать mock, чтобы изменить значение, возвращаемое с помощью uses_some_other_method()
чтобы при каждом вызове в Foo
он возвращал то, что я определил в @patch.object(...)
Ответы
Ответ 1
Есть два способа сделать это; с патчем и с patch.object
Патч предполагает, что вы не импортируете объект напрямую, а тот, который используется объектом, который вы тестируете, как в следующем
#foo.py
def some_fn():
return 'some_fn'
class Foo(object):
def method_1(self):
return some_fn()
#bar.py
import foo
class Bar(object):
def method_2(self):
tmp = foo.Foo()
return tmp.method_1()
#test_case_1.py
import bar
from mock import patch
@patch('foo.some_fn')
def test_bar(mock_some_fn):
mock_some_fn.return_value = 'test-val-1'
tmp = bar.Bar()
assert tmp.method_2() == 'test-val-1'
mock_some_fn.return_value = 'test-val-2'
assert tmp.method_2() == 'test-val-2'
Если вы напрямую импортируете тестируемый модуль, вы можете использовать patch.object следующим образом:
#test_case_2.py
import foo
from mock import patch
@patch.object(foo, 'some_fn')
def test_foo(test_some_fn):
test_some_fn.return_value = 'test-val-1'
tmp = foo.Foo()
assert tmp.method_1() == 'test-val-1'
test_some_fn.return_value = 'test-val-2'
assert tmp.method_1() == 'test-val-2'
В обоих случаях some_fn будет "un-mocked" после завершения тестовой функции.
Изменить:
Чтобы издеваться над несколькими функциями, просто добавьте больше декораторов в функцию и добавьте аргументы, чтобы взять дополнительные параметры
@patch.object(foo, 'some_fn')
@patch.object(foo, 'other_fn')
def test_foo(test_other_fn, test_some_fn):
...
Обратите внимание, что чем ближе декоратор к определению функции, тем раньше он находится в списке параметров.
Ответ 2
Это можно сделать примерно так:
# foo.py
class Foo:
def method_1():
results = uses_some_other_method()
# testing.py
from mock import patch
@patch('Foo.uses_some_other_method', return_value="specific_value"):
def test_some_other_method(mock_some_other_method):
foo = Foo()
the_value = foo.method_1()
assert the_value == "specific_value"
Вот источник, который вы можете прочитать: исправления в неправильном месте
Ответ 3
Позвольте мне прояснить, о чем вы говорите: вы хотите протестировать Foo
в тестовом примере, который вызывает внешний метод uses_some_other_method
. Вместо того, чтобы вызывать реальный метод, вы хотите смоделировать возвращаемое значение.
class Foo:
def method_1():
results = uses_some_other_method()
def method_n():
results = uses_some_other_method()
Хорошо, предположим, что приведенный выше код находится в foo.py
, uses_some_other_method
в модуле bar.py
Вот тестовый блок:
import unitest
import mock
from foo import Foo
class TestFoo(unittest.TestCase):
def setup(self):
self.foo = Foo()
@mock.patch('foo.uses_some_other_method')
def test_method_1(self, mock_method):
mock_method.return_value = 3
self.foo.method_1(*args, **kwargs)
mock_method.assert_called_with(*args, **kwargs)
Если вы хотите изменять возвращаемое значение каждый раз, когда передаете различные аргументы, mock
предоставляет side_effect
.