Для любого класса с методом экземпляра foo
, который зависит от переменной экземпляра, например,
class A:
def __init__(self, x: int):
self.x = x
def foo(self, y: int):
return self.x * y
def test_foo(mocker):
a = A(1)
y = -10
assert a.foo(y) < 0
mocker.patch.object(a, "foo", return_value=a.x * abs(y))
assert a.foo(y) > 0
. Вопрос в том, как имитировать A(1).foo(y)
только для интересующего тестового значения, например, y < 0
, в противном случае верните исходный вызов A(1).foo(y)
? В приведенном выше примере значение y
уже известно, но для этого вопроса, пожалуйста, предположим, что оно неизвестно (скажем, в стороннем коде), и его необходимо проверить по вызову foo()
. Кажется, что python mocks применяются ко всем вызовам к A(1).foo(y)
без каких-либо опций, чтобы применять mock только для указанных c значений y
, проверяя аргументы вызова метода.
Например, используя pytest-mock, приведенный выше тест работает, но у него нет опций для проверки вызова метода, проверки аргументов для вызова метода и внедрения макета только в том случае, если аргументы соответствуют некоторым интересующим значениям и в противном случае вызывают оригинальный метод.
Является ли решение для создания подкласса A
, который может проверять аргументы и возвращать фиктивное значение или вызывать super, а затем использовать mock для внедрения этого подкласса вместо A
? Например, основываясь на приведенном выше примере кода:
class B(A):
def foo(self, y: int):
if y < 0:
return self.x * abs(y)
else:
super().foo(y)
def test_b_foo(mocker):
a = A(1)
y = -10
assert a.foo(y) < 0
mocker.patch.object(A, "foo", side_effect=B(a.x).foo)
assert a.foo(y) > 0
Это работает нормально, но предполагает, что A
уже инициализирован, и использует экземпляр a
для инициализации B
. Как может фиктивная замена звонков на A(i)
звонками на B(i)
, чтобы тест на самом деле звонил на B(i).foo(y)
? Что происходит, когда макеты для указанного c аргумента A(i).foo(y)
для какого-либо указанного c y
должны применяться к методу A.foo
независимо от того, как или когда он инициализируется? Я ищу что-то вроде ruby mocks, которые применяют возвращаемое значение mock только при вызове исправленного объекта (метода) с некоторыми заданными c аргументами. Кажется, что какой-то шпион может динамически вводить возвращаемое значение, когда обнаруживает вызов метода с указанными c аргументами (для короткого замыкания исходного метода), но в противном случае вызывает оригинальный метод. Я думаю, это будет что-то вроде:
m = mock.patch.object(A, "foo")
m.called_with(y < 0).return_value = mock_specific_to_args
# otherwise m.foo(10) calls the original method