2017-11-02 1 views
0

Ich war kürzlich auf einem TDD-Kurs, und ich habe versucht, die Erkenntnisse in die Praxis umzusetzen. Ich habe an Code gearbeitet, um einige JSON-Dokumente zu verarbeiten, die Funktionen enthalten, die ein wenig Verarbeitung machen, und dann andere Funktionen aufrufen, um Teile der Arbeit zu erledigen.TDD in Python: Abhängigkeitsinjektion für Funktionen

Also ruft Funktion 1 innerhalb einer Klasse die Funktion 2 auf, die dann Funktion 3 usw. aufruft. Ich habe die Abhängigkeitsinjektion verwendet, um Funktion 2 zu simulieren, so dass ich Aussagen darüber machen kann, wie Funktion 2 von Funktion 1 aufgerufen wurde Dazu muss der Mock als Parameter an die Funktion 1 übergeben werden, was bei der isolierten Entwicklung der Funktionen gut funktioniert. Wenn ich jedoch den Code für real ausführen und alle unabhängig getesteten Funktionen zusammenstring, stoße ich auf Probleme. Ich kann es anscheinend nicht zum Laufen bringen, wenn ich meine eigentliche Funktion übergeben möchte. Der folgende Code funktioniert nicht, würde aber hoffentlich illustrieren, was ich zu tun versuche.

class myclass: 

    def function1(self, number, injected_function=function2): 
     number = number + 1 
     injected_function(number) 

    def function2(self, number): 
     number = number + 2 
     print(number) 

instantiated_class = myclass() 
instantiated_class.function1(1) 

Normalerweise würde ich so etwas tun:

class myclass: 

    def function1(self, number): 
     number = number + 1 
     self.function2(number) 

    def function2(self, number): 
     number = number + 2 
     print(number) 

instantiated_class = myclass() 
instantiated_class.function1(1) 

Aber dann offensichtlich macht es schwieriger zu testen, wie Funktion 2 genannt wurde. Ich weiß, dass unittest.mock.patch in diesem Szenario verwendet werden kann, aber ist das wirklich die Lösung für all dies? Es fühlt sich an, als würde ich etwas grundsätzlich falsch machen - habe ich den Ansatz falsch mit diesem TDD Zeug?

+0

Wie funktioniert es nicht? Gibt es eine Fehlerausgabe? – MrJLP

+0

@MrJLP Wenn Sie versuchen, den Code im ersten Block auszuführen, wird der Fehlertyp angezeigt. Ich mache mir Sorgen, dass ich nur die falsche Art von Design verwende, um zu erreichen, was ich tun möchte - das ist die Option, während des Testens eine Mock-Funktion einzufügen, ansonsten verwende einfach eine Standardfunktion – millsy

Antwort

0

Es wäre hilfreich, wenn Sie der Frage hinzufügen, welchen Fehler Sie bekommen.

Ausführen Ihres Codes mit Python 3.5 gibt mir NameError: name 'function2' is not defined.

Das Problem ist, dass bei function1 Definition Zeit function2 noch nicht definiert ist. Deklarieren es vor function1 wird dieses Problem lösen:

class myclass: 

    def function2(self, number): 
     number = number + 2 
     print(number) 

    def function1(self, number, injected_function=function2): 
     number = number + 1 
     injected_function(number) 

Das wird noch nicht alles reparieren. Was hier schwierig ist, ist, dass Sie function2 direkt referenzieren und nicht durch myclass, so dass es nicht an die Klasse gebunden ist, wenn Sie injected_function(number) aufrufen. Dies bedeutet, dass der Parameter self ihm nicht automatisch zur Verfügung gestellt wird. Daher wird function2 das Argument number "sehen", das Sie als self übergeben haben, und dann wird es sich beschweren, dass es sein zweites Argument number nicht erhalten hat.

Sie können dies lösen, indem Sie injected_function(self, number) aufrufen, aber das hat nur ein Potenzial für mehr Ärger. Stattdessen können Sie etwas tun:

class myclass: 
    def function1(self, number, injected_function=None): 
     if injected_function is None: 
      injected_function = self.function2 
     number = number + 1 
     injected_function(number) 

    def function2(self, number): 
     number = number + 2 
     print(number) 

Dies funktioniert, weil Sie einen Verweis auf function2 verwenden, die innerhalb self gefunden wird. Es wird also zur Definitionszeit nicht benötigt und der Parameter self wird an den Methodenaufruf gebunden. Zur gleichen Zeit werden Sie kein Problem haben, Funktionen zu liefern, die keine Methoden sind (solche, die keinen self Parameter annehmen).

Verwandte Themen