2017-02-16 1 views
3

Ich versuche zu verstehen, die verschiedenen Möglichkeiten, eine Konstante in Python mit mock.patch zu patchen. Mein Ziel ist es, eine Variable, die in meiner Test-Klasse definiert ist, als Patch-Wert für meine Konstante zu verwenden.Wie packe ich eine Konstante in Python mit einem Mock als Funktion Parameter

Ich habe diese Frage gefunden, die erklärt, wie eine Konstante patchen: How to patch a constant in python Und diese Frage, die erklärt, wie selbst in Patch verwenden: using self in python @patch decorator

Aber aus dieser zweiten Verbindung, kann ich nicht die bekommen testTwo Art und Weise (die Mock als Funktionsparameter bereitstellt)

Hier zu arbeiten ist mein vereinfachte Anwendungsfall:

mein module.py

MY_CONSTANT = 5 

def get_constant(): 
    return MY_CONSTANT 

test_mymodule.py

import unittest 
from unittest.mock import patch 

import mymodule 

class Test(unittest.TestCase): 

    #This works 
    @patch("mymodule.MY_CONSTANT", 3) 
    def test_get_constant_1(self): 
     self.assertEqual(mymodule.get_constant(), 3) 

    #This also works 
    def test_get_constant_2(self): 
     with patch("mymodule.MY_CONSTANT", 3): 
      self.assertEqual(mymodule.get_constant(), 3) 

    #But this doesn't 
    @patch("mymodule.MY_CONSTANT") 
    def test_get_constant_3(self, mock_MY_CONSTANT): 
     mock_MY_CONSTANT.return_value = 3 
     self.assertEqual(mymodule.get_constant(), 3) 
     #AssertionError: <MagicMock name='MY_CONSTANT' id='64980808'> != 3 

Meine Vermutung ist shoudln't ich return_value, verwenden, da mock_MY_CONSTANT keine Funktion ist. Welches Attribut soll ich also verwenden, um den zurückgegebenen Wert zu ersetzen, wenn die Konstante aufgerufen wird?

Antwort

-1

Sie simpy können vor jeder Assertion Mock Wert konstant zu:

def test_get_constant_3(self): 
    mymodule.MY_CONSTANT = 3 
    self.assertEqual(mymodule.get_constant(), 3) 
    mymodule.MY_CONSTANT = 7 
    self.assertEqual(mymodule.get_constant(), 7) 

Einige weiteres Beispiel

# --- config.py --- 

class AppConf: 
    APP_TIMEZONE = os.environ.get['APP_TIMEZONE'] 



# --- my_mod.py --- 

from datetime import datetime 
from config import AppConf 

LOCAL_TZ = AppConf.APP_TIMEZONE 

def to_local_tz(dt_obj, tz): 
    """Return datetime obj for specific timezone""" 
    # some code here 
    return local_dt_obj 

def get_local_time(): 
    return to_local_tz(datetime.utcnow(), LOCAL_TZ).strftime('%H:%M') 



# --- test_my_mod.py --- 

import my_mod 

class TestMyMod(unittest.TestCase): 
    @patch('my_mod.datetime') 
    def test_get_local_time(self, mock_dt): 
     # Mock to 15:00 UTC 
     mock_dt.utcnow.return_value = datetime(2017, 5, 3, 15) 

     # Test with TZ 'Europe/Kiev'  +02:00 +03:00(DST) 
     my_mod.LOCAL_TZ = 'Europe/Kiev' 
     assert my_mod.get_local_time() == '18:00' 

     # Test with TZ 'America/New_York' -05:00 -04:00(DST) 
     my_mod.LOCAL_TZ = 'America/New_York' 
     assert my_mod.get_local_time() == '11:00' 

Also keine Notwendigkeit, eine Konstante patchen gar

+0

Zuerst vielen Dank für Ihre Antwort! Ja, aber in diesem Fall bedeutet dies, dass der Wert von mymodule.MY_CONSTANT für alle folgenden Tests geändert wird. Deshalb möchte ich stattdessen patch verwenden, so dass es auf den Bereich beschränkt ist, in dem ich patche. –

+0

Dann verwenden Sie 'mit patch():' für Ihren Fall. Was brauchst du mehr? Ich kann das Problem nicht verstehen, tut mir leid. –

+0

In Variante # 3 bekommst du sowieso das gleiche Ergebnis wie # 2, warum willst du sowas wie # 3 Format? –

0

Zur Beantwortung der Frage theoretisch denke ich, dass Sie die __int__() Methode auf die Konstante patchten müssen, so:

@patch("mymodule.MY_CONSTANT.__int__") 
def test_get_constant_4(self, mock_MY_CONSTANT): 
    mock_MY_CONSTANT.return_value = 3 
    self.assertEqual(mymodule.get_constant(), 3) 

Offensichtlich ist dies der falsche Weg, wie der Fehler zeigt.

AttributeError: 'int' object attribute '__int__' is read-only 
Verwandte Themen