2016-11-15 2 views
1

Ich habe einige Probleme beim Patchen einer Klasse mit einer Funktion und einer Eigenschaft.Python-Mock-Klasse mit Funktion und Eigenschaft

Die Projektstruktur arbeite ich mit sich wie folgt:

project 
|- src 
| |- logic 
| | |- sub_logic 
| | | | __init__.py 
| | | | cache.py 
| | | | manager.py 
| | | __init__.py 
|- test 
| | test.py 

Meine Cache-Datei wie diese ähnliche

from cache import Cache 


class Manager(object): 
    def __init__(self): 
     self._cache = Cache(20) 

    def do_something(self): 
     if self._cache.Val != 20: 
      raise ValueError(u"Val is not 20") 

     return True 

    def do_something_else(self): 
     if self._cache.other_function(): 
      raise ValueError(u"Something is True") 

Die Tests

class Cache(object): 
    def __init__(self, val): 
     self._val = val 

    @property 
    def Val(self): 
     return self._val 

    def other_function(self): 
     return False 

Der Manager-Datei sieht sieht Ich habe versucht folgendes zu machen:

from unittest import TestCase 
from mock import PropertyMock, patch 

from logic.sub_logic.manager import Manager 
from logic.sub_logic.cache import Cache 


class ManagerTestCase(TestCase): 

    def test_01_cache(self): 
     manager = Manager() 
     self.assertEqual(manager.do_something(), True) 

    @patch('logic.sub_logic.manager.Cache.Val', new_callable=PropertyMock) 
    def test_02_cache(self, property_mock): 
     property_mock.return_value = 20 
     manager = Manager() 
     self.assertEqual(manager.do_something(), True) 

    @patch('logic.sub_logic.manager.Cache', spec=Cache) 
    def test_03_cache(self, cache_mock): 
     cache_mock.other_function.return_value = True 
     manager = Manager() 
     with self.assertRaises(ValueError): 
      manager.do_something_else() 

    @patch('logic.sub_logic.manager.Cache', spec=Cache) 
    def test_04_cache(self, cache_mock): 
     cache_mock.other_function.return_value = True 
     cache_mock.Val = PropertyMock() 
     cache_mock.Val.return_value = 20 

     manager = Manager() 
     with self.assertRaises(ValueError): 
      manager.do_something_else() 
     self.assertEqual(manager.do_something(), True) 

    @patch('logic.sub_logic.manager.Cache.Val', new_callable=PropertyMock) 
    @patch('logic.sub_logic.manager.Cache', spec=Cache) 
    def test_05_cache(self, cache_mock, property_mock): 
     cache_mock.other_function.return_value = True 
     property_mock.return_value = 20 
     manager = Manager() 
     with self.assertRaises(ValueError): 
      manager.do_something_else() 
     self.assertEqual(manager.do_something(), True) 

    @patch('logic.sub_logic.manager.Cache', spec=Cache) 
    def test_06_cache(self, cache_mock): 
     cache_mock.other_function.return_value = True 
     cache_mock.Val = 20 

     manager = Manager() 
     with self.assertRaises(ValueError): 
      manager.do_something_else() 
     self.assertEqual(manager.do_something(), True) 

Das Problem ist, dass test_04_cache und test_05_cache nicht funktionieren. Beim Debuggen der Tests ist der angegebene Mock-Parameter so, wie ich es erwartet hatte. Aber der Manager erstellt eine MagicMock, wobei die Eigenschaft Val keine PropertyMock, sondern eine MagicMock ist.

Ich inspizierte test_06_cache in PyCharm-Debugger, berichtet folgendes:

  • cache_mock.Val = {int}20
  • manager._cache.Val = {MagicMock}<MagicMock name='Cache().Val' id='61044848'>

ich etwas fehlt? Oder ist das nicht möglich?

+0

Wenn Sie den Cache sind spöttisch aus, warum fragst du, ob es wirklich implementiert ist als Eigentum? Setze einfach 'cache_mock.Val = 20'. – jonrsharpe

+0

Sie schlagen vor, 'cache_mock.Val = PropertyMock() cache_mock.Val.return_value = 20' mit nur' cache_mock.Val = 20' zu ersetzen? Ich habe das gerade versucht und es scheint nicht zu funktionieren. – KlemensE

+0

In test_05 machst du zuerst Cache.Val, aber danach verspottet du Cache, der das ganze Objekt durch MagicMock ersetzt. Deshalb sehen Sie in test_05 Val als MagicMock. – marxin

Antwort

3

Wenn Sie

@patch('logic.sub_logic.manager.Cache', spec=Cache) 

die resultierende Mock verwenden ist für die Klasse. Ihre Manager erstellt dann eine Instanz von Aufruf dieser Klasse, in __init__. Daher sollten Sie Attribute und Rückgabewerte unter mock_cache() (in Klammern) festlegen. Dies ist die "Instanz", die manager._cache zugewiesen wird, und nicht die "Klasse" mock_cache.

Bitte beachte, dass, da der Manager nicht weiß, dass der Cache-Speicher ein @property verwendet, können Sie gerade eingestellt:

mock_cache().Val = 20 
Verwandte Themen