2016-08-15 3 views
0

Ich habe eine Klasse in meinem Code, der eine Drittanbieter-Bibliothek verwendet. Ich möchte mich über die Instanzmethode des Objekts lustig machen, die ich durch Aufruf einer Instanzmethode der Bibliotheksklasse erhalte. Mir ist nicht klar, wie ich die Instanzmethode dieses inneren Objekts verspotten soll. Im Anschluss ist mein Code:Mocking eine Instanz Methode des inneren Objekts in Python 3.4

Meine Klasse:

from a import A 

class MyClass(object): 
    def __init__(self): 
     self.obj = A() 

    def do_something(self): 
     b = self.obj.get_inner_object() 
     result = b.do_inner() 
     return result 

Hier ist meine Testklasse ist:

from unittest import TestCase 
from unittest.mock import MagicMock 
from unittest.mock import patch 
from a import A 
class TestMyClass(TestCase): 
    def __init__(self): 
     self.my_class = MyClass() 

    @patch.object(A,'get_inner_object') 
    def test_do_something(self, mock_get_inner_object): 
     test_res = self.my_class.do_something() 

Wie Sie oben sehen können, würde Ich mag weg 2 Methoden meiner Bibliothek verspotten - get_inner_object() und do_inner() ist die Instanzmethode des Objekts, das von get_inner_object() zurückgegeben wird. Ich konnte get_inner_object() vortäuschen, aber ich weiß nicht, wie ich die do_inner() -Methode verspotten soll. Bitte klären Sie. Hier ist die Hilfe, die ich folgende bin: https://www.toptal.com/python/an-introduction-to-mocking-in-python

+0

Wenn Sie verspotten 'get_inner_object' es wird bereits ein Modell zurückkehren, auf dem Sie' do_inner' aufrufen können. – jonrsharpe

+0

sicher, aber wie weiß 'MyClass' über dieses Mock-Objekt, da ich es nicht an 'MyClass' übergebe? –

+0

Was meinst du * "weiß es" * ?! Es "weiß" * nichts, es macht nur die Anrufe oder wirft einen Fehler, wenn es nicht möglich ist, ob es ein Schein ist oder nicht. Aus Ihrem Beispiel sieht es so aus, als ob Sie sich über "A" lustig machen sollten, da es sonst keine Möglichkeit gibt, es zu injizieren. – jonrsharpe

Antwort

0

Nur verspotten alle A:

@patch('a.A') 
def test_do_something(self, mock_A): 
    mock_b = mock_A.return_value.get_inner_object.return_value 
    mock_b.do_inner.return_value = 'mocked return value' 

    test_res = self.my_class.do_something() 

    self.assertEqual(test_res, 'mocked return value') 

Immerhin Sie testen MyClass hier nicht A.

So oder so, ob Sie @patch.object(A, 'get_inner_object') verwenden oder alle A Patch, der self.obj.get_inner_object() Ausdruck eine Mock Instanz aufruft, so das .return_value Attribut wird an diesem Punkt zurück. Die Methode do_inner ist nur ein weiterer angeketteter Aufruf, bei dem der Schein hier zurückgegeben wurde. Sie können also festlegen, was für diese Methode zurückgegeben wird, indem Sie das Attribut .return_value auf etwas setzen, das Sie testen.

Um das zu übersetzen, um Ihre @patch.object() Situation zurück, mock_b ist dann die mock_inner_object.return_value Objekt:

@patch.object(A,'get_inner_object') 
def test_do_something(self, mock_get_inner_object): 
    mock_b = mock_get_inner_object.return_value 
    mock_b.do_inner.return_value = 'mocked return value' 

    test_res = self.my_class.do_something() 

    self.assertEqual(test_res, 'mocked return value') 
+0

Ich folgte dem oben genannten Ansatz, um den return_value meiner do_inner Methode zu setzen, aber wenn ich den Test ausführe, bekomme ich nicht den Wert, den ich in return_value gesetzt habe, stattdessen bekomme ich object was ich nicht bin in der Lage zu validieren. Irgendeine Idee, was ich hier vermisse? –

+0

@RakeshK: dann ist Ihr Call Graph noch anders; Ihr Code hat schließlich ein Mock-Objekt aufgerufen, für das Sie keinen '.return_value' festgelegt haben. Sie können überprüfen, was aufgerufen wurde, indem Sie 'mock_get_inner_object.mock_calls' drucken. –

+0

@RakeshK: siehe https://bpaste.net/show/e4663a19302d für ein Beispiel; dort wird die verspottete Klasse "A" aufgerufen, dann wurde auf dem Mock-Objekt "mockA.return_value" 'get_inner_object()' aufgerufen, dann wurde "do_inner()" an * that * aufgerufen. Daher wird das vollständige Anrufdiagramm für diesen zuletzt aufgezeichneten Anruf durch "mockA.return_value.get_inner_object.return_value.do_inner.return_value" wiedergegeben. –

Verwandte Themen