Python unittest mock: Ist es möglich, den Wert der Standard-Argumente einer Methode zur Testzeit zu verspotten?

Ich habe eine Methode, die Standard-Argumente akzeptiert:

def build_url(endpoint, host=settings.DEFAULT_HOST): return '{}{}'.format(host, endpoint) 

Ich habe einen Testfall, der diese Methode ausübt:

 class BuildUrlTestCase(TestCase): def test_build_url(self): """ If host and endpoint are supplied result should be 'host/endpoint' """ result = build_url('/end', 'host') expected = 'host/end' self.assertEqual(result,expected) @patch('myapp.settings') def test_build_url_with_default(self, mock_settings): """ If only endpoint is supplied should default to settings""" mock_settings.DEFAULT_HOST = 'domain' result = build_url('/end') expected = 'domain/end' self.assertEqual(result,expected) 

Wenn ich einen Debug-Punkt in build_url und diese Attribut- settings.DEFAULT_HOST überprüfe.DEFAULT_HOST gibt den verspotten Wert zurück. Allerdings fährt der Test weiterhin aus und die Behauptung zeigt an, dass host den Wert aus meinen aktuellen settings.py zugewiesen hat. settings.py . Ich weiß, das ist, weil das host Keyword-Argument auf die Importzeit gesetzt ist und mein Schein nicht berücksichtigt wird.

Debugger

 (Pdb) settings <MagicMock name='settings' id='85761744'> (Pdb) settings.DEFAULT_HOST 'domain' (Pdb) host 'host-from-settings.com' 

Gibt es eine Möglichkeit, diesen Wert zu Testzeit zu überschreiben, damit ich den Standardpfad mit einem verspotten settings ausüben kann?

2 Solutions collect form web for “Python unittest mock: Ist es möglich, den Wert der Standard-Argumente einer Methode zur Testzeit zu verspotten?”

Funktionen speichern ihre Parameter-Standardwerte im Attribut func_defaults , wenn die Funktion definiert ist, also kannst du das patchen. Etwas wie

 def test_build_url(self): """ If only endpoint is supplied should default to settings""" with patch.object(build_url, 'func_defaults', ('domain',)): result = build_url('/end') expected = 'domain/end' self.assertEqual(result,expected) 

Ich verwende patch.object als Kontextmanager und nicht als Dekorateur, um zu vermeiden, dass das unnötige test_build_url als Argument für test_build_url .

Ich habe die andere Antwort auf diese Frage angewendet, aber nach dem Kontext-Manager war die gepatchte Funktion nicht die gleiche wie vorher.

Meine gepatchte Funktion sieht so aus:

 def f(foo=True): pass 

In meinem Test habe ich das gemacht:

 with patch.object(f, 'func_defaults', (False,)): 

Beim Aufruf von f nach (nicht in) des Kontextmanagers war die Voreinstellung völlig weg, anstatt auf den vorherigen Wert zurückzukehren. Aufruf f ohne Argumente gab den Fehler TypeError: f() takes exactly 1 argument (0 given)

Stattdessen habe ich das schon vor meinem Test gemacht:

 f.func_defaults = (False,) 

Und das nach meinem Test:

 f.func_defaults = (True,) 
  • Mocking nur eine einzige Methode auf ein Objekt
  • Mock / patch os.path.exists mit mehreren Rückgabewerten
  • Mocking-Test in Django nicht funktioniert, wenn alles läuft in TestCase aber funktioniert gut eins nach dem anderen
  • Ist es möglich, Pythons eingebaute Druckfunktion zu verspotten?
  • Assert eine Funktion / Methode wurde nicht mit Mock aufgerufen
  • Patch __call__ einer Funktion
  • Wie soll ich eine Log-Meldung beim Testen von Python-Code unter Nase überprüfen?
  • Pythonschock und Bibliotheken, die nicht installiert sind
  • Einen Wrapper für `mock.patch` machen
  • Wie kann ich das Dateisystem in python-Unit-Tests verspotten?
  • Testen argparse mit unbescheidenen und verspotten
  • Python ist die beste Programmiersprache der Welt.