Mock-Attribute in Python-Mock?

76

Ich habe eine ziemlich schwierige Zeit mockin Python:

def method_under_test():
    r = requests.post("http://localhost/post")

    print r.ok # prints "<MagicMock name='post().ok' id='11111111'>"

    if r.ok:
       return StartResult()
    else:
       raise Exception()

class MethodUnderTestTest(TestCase):

    def test_method_under_test(self):
        with patch('requests.post') as patched_post:
            patched_post.return_value.ok = True

            result = method_under_test()

            self.assertEqual(type(result), StartResult,
                "Failed to return a StartResult.")

Der Test gibt tatsächlich den richtigen Wert zurück, r.okist jedoch kein Mock-Objekt True. Wie verspotten Sie Attribute in Pythons mockBibliothek?

Naftuli Kay
quelle

Antworten:

92

Sie müssen verwenden return_valueund PropertyMock:

with patch('requests.post') as patched_post:
    type(patched_post.return_value).ok = PropertyMock(return_value=True)

Dies bedeutet: Wenn Sie aufrufen requests.post, setzen Sie für den Rückgabewert dieses Aufrufs ein PropertyMockfür die Eigenschaft ok, um den Wert zurückzugeben True.

Simeon Visser
quelle
Wenn ich printden Wert von r.okvon in der method_under_test, sehe ich <MagicMock name='post().ok' id='57360464'>nicht True.
Naftuli Kay
@TKKocheran: Ich habe meine Antwort aktualisiert. Sie müssen auch a verwenden PropertyMock.
Simeon Visser
13
Warum nicht einfach benutzen patched_post.return_value = mock.Mock(ok=True)?
Lumbric
3
@lumbric Weil Sie damit bestätigen können PropertyMock, dass wie bei jedem anderen MockObjekt darauf zugegriffen wurde . Wenn Sie der Eigenschaft nur einen Wert zuweisen, können Sie dies nicht tun.
Bono
20

Eine kompakte und einfache Möglichkeit besteht darin, new_callable patchdas Attribut 's patchzu verwenden , um die Verwendung zu erzwingen , PropertyMockanstatt MagicMockdas Scheinobjekt zu erstellen. Die anderen übergebenen Argumente patchwerden zum Erstellen eines PropertyMockObjekts verwendet.

with patch('requests.post.ok', new_callable=PropertyMock, return_value=True) as mock_post:
    """Your test"""
Michele d'Amico
quelle
15

Mit der Scheinversion '1.0.1' wird die in der Frage erwähnte einfachere Syntax unterstützt und funktioniert wie sie ist!

Beispielcode aktualisiert (py.test wird anstelle von unittest verwendet):

import mock
import requests


def method_under_test():
    r = requests.post("http://localhost/post")

    print r.ok

    if r.ok:
        return r.ok
    else:
        raise Exception()


def test_method_under_test():
    with mock.patch('requests.post') as patched_post:
        patched_post.return_value.ok = True

        result = method_under_test()
        assert result is True, "mock ok failed"

Führen Sie diesen Code aus mit: (Stellen Sie sicher, dass Sie pytest installieren)

$ py.test -s -v mock_attributes.py 
======= test session starts =======================
platform linux2 -- Python 2.7.10 -- py-1.4.30 -- pytest-2.7.2 -- /home/developer/miniconda/bin/python
rootdir: /home/developer/projects/learn/scripts/misc, inifile: 
plugins: httpbin, cov
collected 1 items 

mock_attributes.py::test_method_under_test True
PASSED

======= 1 passed in 0.03 seconds =================
Howaryoo
quelle
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klärung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag. Sie können jederzeit Ihre eigenen Beiträge kommentieren. Sobald Sie einen ausreichenden Ruf haben, können Sie jeden Beitrag kommentieren .
Philant
Zu Ihrer Information requests.post.okist eine Eigenschaft und kein Attribut. Wenn Sie ein einfaches Objekt anprobieren, bei dem okes sich um ein einfaches Attribut handelt , funktioniert die in der Frage erwähnte Syntax, aber für requests.post.okObjekt Nr AttributeError.
Michele d'Amico
@philant danke für Ihr Feedback, wie das Beispiel zeigt, ist dies die aktuelle Antwort auf die Frage und die Syntax ist viel einfacher.
Howaryoo
@ Micheled'Amico danke für dein Feedback, ich habe versucht, bitte einen Blick darauf zu werfen ;-)
Howaryoo