2017-02-22 1 views
2

Ich versuche os.environ in einer Klasse zu verspotten, aber ich kann es einfach nicht richtig machen. Hier ist meine Struktur:Python mock os.environ in einer Klasse verwendet

#file.py 
import os 

class MyClass(): 
    connection_url = os.environ['DB'] 

#some code 

Und hier ist mein Test (letzter Versuch, sowieso):

#test.py 
from unittest import TestCase 
from unittest.mock import patch 
from file import MyClass 

class TestMyClass(TestCase): 
    @patch.dict('file.os.environ', {'DB' : 'Dummy' }) 
    def setUp(self): 
     self.class = MyClass() 

#some testing 

Dies ist kläglich versagt, KeyError 'DB' Anheben ... Kann mir jemand helfen? Ich bin neu in Python-Unittests. Ich recherchierte einige Blogs und Stackoverflow, versuchte einige Lösungen, konnte es aber nicht richtig machen.

Vielen Dank im Voraus!

Antwort

1

Das Problem hierbei ist, dass connection_url gesetzt, wenn die Klasse (beim Import) erstellt wird. Wenn Sie es verspotten wollen, können Sie das Attribut auf die Klasse Patch selbst, bevor Sie verwenden das Attribut:

class TestMyClass(TestCase): 
    @patch.object(file.MyClass, 'connection_url', 'Dummy') 
    def setUp(self): 
     self.instance = MyClass() 

Sie werden immer noch mit dem Potenzial KeyError beim Import zu tun haben - das heißt, Sie‘ ll müssen sicherstellen, dass Ihre Test-Runner eine Dummy-Wert in der Umgebung hat, bevor Sie Importdatei sonst werden Sie den Code in file.py ändern müssen, um sicherzustellen, dass es keinen Anlass zu einer KeyError. Es gibt ein paar Strategien hier. Sie können nur die KeyErrorconnection_url = default_value lassen unterdrücken, wenn sie nicht in der Umwelt festgelegt wurde:

Oder Sie können die connection_url in __init__ Holen bewegen:

class MyClass(): 
    def __init__(self): 
     connection_url = os.environ['DB'] 

Dieser letztere Code hat den zusätzlichen Vorteil, dass Ihre patch.dict sollte anfangen zu arbeiten.

Beachten Sie, dass die Instanz nur die gepatchte während der setUp-Methode hat, wenn Sie einen der beiden ersten Ansätze wählen - die folgenden Tests werden nicht gepatcht haben. Es ist sehr wahrscheinlich, dass dies ein Show-Stopper und Sie werden eine neue Instanz in jedem Test erstellen müssen, die Sie haben:

class TestMyClass(TestCase): 
    @patch.object(file.MyClass, 'connection_url', 'Dummy') 
    def test_first_thing(self): 
     self.instance = MyClass() 
     ... 

    @patch.object(file.MyClass, 'connection_url', 'Dummy') 
    def test_second_thing(self): 
     self.instance = MyClass() 
     ... 
+0

Ich denke, das an der falschen Stelle ist das Patchen, weil 'os.environ [‘ Auf DB '] 'wird immer noch zugegriffen (und möglicherweise' KeyError', wenn es nicht in Testumgebung konfiguriert ist). Ich meine, der OP-Code erhöht sich zum Zeitpunkt des Imports, nicht zum Zeitpunkt der Einrichtung, also wird der Patch nicht helfen. – wim

+0

@wim - Absolut. Das Problem ist, dass Sie etwas zum Importzeitpunkt nicht packen können. Alles, was Sie tun können, ist das Objekt zu patchen, wenn Sie es verwenden wollen. Dies ersetzt den Wert, den 'connection_url' mit dem von OP gewünschten Dummy-Wert hat. Wie Sie bemerken, verhindert es 'KeyError' nicht, wenn' 'DB'' nicht in der Umgebung ist - Der einzige Weg ist es _set_' os.environ' _vor dem Importieren_ irgendeines Codes oder durch Ändern des Nicht-Test-Code ... – mgilson

+0

Daher ist diese Antwort nicht wirklich nützlich. Sobald eine Testmethode versucht, die 'self.instance' zu ​​verwenden, wird eine alte' connection_url' wiederhergestellt. Im 'setUp' finde ich keinen Patch-Punkt. Mit dem Code, den wir gezeigt haben, wird es entweder einen anderen Ansatz oder eine Umstrukturierung der Klasse erfordern. – wim