wake-up-neo.com

Verwenden von pythons mock patch.object, um den Rückgabewert einer in einer anderen Methode aufgerufenen Methode zu ändern

Ist es möglich, einen Rückgabewert einer Funktion zu verspotten, die in einer anderen Funktion aufgerufen wird, die ich zu testen versuche? Ich möchte, dass die verspottete Methode (die in vielen von mir getesteten Methoden aufgerufen wird) bei jedem Aufruf meine angegebenen Variablen zurückgibt. Beispielsweise:

class Foo:
    def method_1():
       results = uses_some_other_method()
    def method_n():
       results = uses_some_other_method()

Im Unit-Test möchte ich mock verwenden, um den Rückgabewert von uses_some_other_method() so zu ändern, dass bei jedem Aufruf in Foo das zurückgegeben wird, was ich in @patch.object(...)

51
mdoc-2011

Es gibt zwei Möglichkeiten, dies zu tun. mit patch und mit patch.object

Patch setzt voraus, dass Sie das Objekt nicht direkt importieren, sondern dass es von dem Objekt verwendet wird, das Sie wie folgt testen

#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'

Wenn Sie das zu testende Modul direkt importieren, können Sie patch.object folgendermaßen verwenden:

#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'

In beiden Fällen wird some_fn nach Abschluss der Testfunktion deaktiviert.

Bearbeiten: Um mehrere Funktionen zu verspotten, fügen Sie der Funktion einfach weitere Dekoratoren und Argumente hinzu, um die zusätzlichen Parameter zu berücksichtigen

@patch.object(foo, 'some_fn')
@patch.object(foo, 'other_fn')
def test_foo(test_other_fn, test_some_fn):
    ...

Beachten Sie, dass die Parameterliste umso früher angezeigt wird, je näher der Dekorator an der Funktionsdefinition ist.

80
Silfheed

Dies kann folgendermaßen geschehen:

# 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"

Hier ist eine Quelle, die Sie lesen können: Patching an der falschen Stelle

13
chipz

Lassen Sie mich klarstellen, wovon Sie sprechen: Sie möchten Foo in einem Testfall testen, der die externe Methode uses_some_other_method Aufruft. Anstatt die eigentliche Methode aufzurufen, möchten Sie den Rückgabewert verspotten.

class Foo:
    def method_1():
       results = uses_some_other_method()
    def method_n():
       results = uses_some_other_method()

Angenommen, der obige Code befindet sich in foo.py, uses_some_other_method Ist in Modul bar.py Definiert. Hier ist das Unanständigste:

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)

Wenn Sie den Rückgabewert bei jeder Übergabe in anderen Argumenten ändern möchten, gibt mockside_effect aus.

5
cizixs