Строгий макет в питоне

Есть ли в Python эквивалент строгих издевательств? Некоторый механизм для сообщения о непреднамеренном вызове фиктивных методов (action.step2 () в этом примере), как в GoogleMock Framework.

class Action:
    def step1(self, arg):
        return False

    def step2(self, arg):
        return False

def algorithm(action):
    action.step1('111')
    action.step2('222')
    return True

class TestAlgorithm(unittest.TestCase):
    def test_algorithm(self):
        actionMock = mock.create_autospec(Action)
        self.assertTrue(algorithm(actionMock))
        actionMock.step1.assert_called_once_with('111')
4 голоса | спросил NiegodziwyBeru 8 J000000Tuesday14 2014, 15:32:05

3 ответа


0

Похоже, это не поддерживается из коробки. Однако есть как минимум два подхода к достижению одного и того же результата.

Список разрешенных участников

Согласно фиктивной документации

  

spec : это может быть список строк или существующий объект (класс или экземпляр), который выступает в качестве спецификации для фиктивного объекта. Если вы передаете объект, то список строк формируется путем вызова dir для объекта (исключая неподдерживаемые магические атрибуты и методы). Доступ к любому атрибуту, отсутствующему в этом списке, вызовет ошибку AttributeError .

Итак, чтобы провалить ваш тестовый пример, просто замените

actionMock = mock.create_autospec(Action)

до

actionMock = mock.Mock(spec=['step1'])

Такой подход имеет определенные недостатки по сравнению с передачей класса или экземпляра в качестве аргумента spec, так как вы должны передать все разрешенные методы и чем возлагать на них надежды, фактически регистрируя их дважды. Кроме того, если вам нужно ограничить подмножество методов, вы должны передать список всех методов, кроме тех. Это может быть достигнуто следующим образом:

all_members = dir(Action)  # according to docs this is what's happening behind the scenes
all_members.remove('step2')  # remove all unwanted methods 
actionMock = mock.Mock(spec=all_members)

Установка исключений для ограниченных методов

Альтернативным подходом было бы явное установление сбоев в методах, которые вы не хотите вызывать:

def test_algorithm(self):
    actionMock = mock.create_autospec(Action)
    actionMock.step2.side_effect = AttributeError("Called step2") # <<< like this
    self.assertTrue(algorithm(actionMock))
    actionMock.step1.assert_called_once_with('111')

Это также имеет некоторые ограничения: вы должны устанавливать ошибки и ожидания.

В качестве последнего замечания, одно радикальное решение этой проблемы будет заключаться в исправлении mock для добавления strict в конструктор Mock и отправьте запрос на извлечение. Чем либо это будет принято, либо сопровождающие mock укажут, как этого добиться. :)

ответил J0HN 9 J000000Wednesday14 2014, 10:37:40
0

Да, это возможно с помощью spec= и autospec= аргументы. Для получения дополнительной информации см. макетную документацию по автоматическому определению В вашем примере это станет:

action_mock = mock.Mock(spec=Action)

или

action_mock = mock.Mock('Action', autospec=True)
ответил Simeon Visser 8 J000000Tuesday14 2014, 17:36:16
0

Еще одна возможность:

Индивидуальная проверка call_count на ограниченных методах

Убедитесь, что call_count равно нулю для методов, которые не следует вызывать.

class TestAlgorithm(unittest.TestCase):
    def test_algorithm(self):
        actionMock = mock.create_autospec(Action)
        self.assertTrue(algorithm(actionMock))
        actionMock.step1.assert_called_once_with('111')
        self.assertEqual(actionMock.step2.call_count, 0) # <<< like this

Недостатком является то, что вы должны проверять все неожиданные вызовы один за другим.

ответил Cilyan 11 J000000Friday14 2014, 01:18:59

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132