2016-11-15 1 views
1

У меня возникли проблемы с исправлением класса с функцией и свойством.Класс python mock с функцией и свойством

Структура проекта Я работаю с выглядит следующим образом:

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

Мой кэш-файл выглядит следующим образом

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

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

    def other_function(self): 
     return False 

Файл менеджер выглядит как этот

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") 

В тестах Я попытался сделать следующее:

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) 

Проблема в том, что test_04_cache и test_05_cache не работают. При отладке тестов параметр макета предоставляется так, как я ожидал. Но Менеджер создает MagicMock, где свойство Val не является PropertyMock, а также MagicMock.

Я осмотрел test_06_cache в PyCharm Debugger, который сообщает следующее:

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

ли я что-то отсутствует? Или это невозможно?

+0

Если вы насмехаясь из кэша, почему вы все равно, если это действительно реализовано как собственность? Просто установите 'cache_mock.Val = 20'. – jonrsharpe

+0

Вы предлагаете заменить 'cache_mock.Val = PropertyMock() cache_mock.Val.return_value = 20' только с' cache_mock.Val = 20'? Я просто попробовал это, и, похоже, это не сработало. – KlemensE

+0

В test_05 вы сначала издеваетесь над Cache.Val, но затем после этого вы издеваетесь над кешем, который заменяет весь объект MagicMock. Вот почему в test_05 вы видите Val как MagicMock. – marxin

ответ

3

При использовании

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

полученный макет предназначен для класса. Затем ваш Manager создает экземпляр , вызывающий этот класс, в __init__. Поэтому вы должны устанавливать атрибуты и возвращаемые значения на mock_cache() (отметить круглые скобки), который является «экземпляром», который будет назначен manager._cache, а не на «классе» mock_cache.

Обратите внимание, что, как менеджер не знает, что кэш использует @property, вы можете просто установить:

mock_cache().Val = 20