Утверждение функции/метода не вызывается с использованием Mock

Я использую библиотеку Mock для тестирования своего приложения, но хочу утверждать, что некоторая функция не вызывалась. Mock docs рассказывают о методах типа mock.assert_called_with и mock.assert_called_once_with, но я не нашел ничего подобного mock.assert_not_called или что-то связанное с проверкой mock было НЕ вызывается.

Я мог бы пойти с чем-то вроде следующего, хотя это не выглядит круто и не pythonic:

def test_something:
    # some actions
    with patch('something') as my_var:
        try:
            # args are not important. func should never be called in this test
            my_var.assert_called_with(some, args)
        except AssertionError:
            pass  # this error being raised means it ok
    # other stuff

Любые идеи, как это сделать?

Спасибо за любую помощь:)

Ответ 1

Это должно работать для вашего случая;

assert not my_var.called, 'method should not have been called'

Пример

>>> mock=Mock()
>>> mock.a()
<Mock name='mock.a()' id='4349129872'>
>>> assert not mock.b.called, 'b was called and should not have been'
>>> assert not mock.a.called, 'a was called and should not have been'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: a was called and should not have been

Ответ 2

Хотя старый вопрос, я хотел бы добавить, что в настоящее время библиотека mock (backport of unittest.mock) поддерживает метод assert_not_called.

Просто обновите свою версию;

pip install mock --upgrade

Ответ 3

Вы можете проверить атрибут called, но если ваше утверждение не удастся, следующая вещь, которую вы хотите узнать, - это что-то о неожиданном вызове, поэтому вы можете также организовать эту информацию, которая будет отображаться с самого начала. Используя unittest, вы можете проверить содержимое call_args_list вместо:

self.assertItemsEqual(my_var.call_args_list, [])

Когда он терпит неудачу, он выдает следующее сообщение:

AssertionError: Element counts were not equal:
First has 0, Second has 1:  call('first argument', 4)

Ответ 4

Когда вы проверяете использование наследований классов unittest.TestCase, вы можете просто использовать такие методы, как:

  • assertTrue
  • assertFalse
  • assertEqual

и аналогичные (в документации python вы найдете все остальное).

В вашем примере мы можем просто утверждать, что свойство mock_method.called False, что означает, что этот метод не был вызван.

import unittest
from unittest import mock

import my_module

class A(unittest.TestCase):
    def setUp(self):
        self.message = "Method should not be called. Called {times} times!"

    @mock.patch("my_module.method_to_mock")
    def test(self, mock_method):
        my_module.method_to_mock()

        self.assertFalse(mock_method.called,
                         self.message.format(times=mock_method.call_count))

Ответ 5

Судя по другим ответам, никто, кроме @rob-kennedy, не говорил о call_args_list.

Это мощный инструмент для того, чтобы вы могли реализовать точное противоречие MagicMock.assert_called_with()

call_args_list - это список объектов call. Каждый call объект представляет собой вызов, сделанный на издеваемом вызываемом.

>>> from unittest.mock import MagicMock
>>> m = MagicMock()
>>> m.call_args_list
[]
>>> m(42)
<MagicMock name='mock()' id='139675158423872'>
>>> m.call_args_list
[call(42)]
>>> m(42, 30)
<MagicMock name='mock()' id='139675158423872'>
>>> m.call_args_list
[call(42), call(42, 30)]

Потребление объекта call прост, так как вы можете сравнить его с кортежем длины 2, где первый компонент представляет собой кортеж, содержащий все позиционные аргументы связанного вызова, тогда как второй компонент является словарем ключевого слова аргументы.

>>> ((42,),) in m.call_args_list
True
>>> m(42, foo='bar')
<MagicMock name='mock()' id='139675158423872'>
>>> ((42,), {'foo': 'bar'}) in m.call_args_list
True
>>> m(foo='bar')
<MagicMock name='mock()' id='139675158423872'>
>>> ((), {'foo': 'bar'}) in m.call_args_list
True

Таким образом, способ решения конкретной проблемы OP -

def test_something():
    with patch('something') as my_var:
        assert ((some, args),) not in my_var.call_args_list

Обратите внимание, что таким образом, вместо того, чтобы просто проверять, был ли вызван вымышленный вызываемый вызов, через MagicMock.called вы можете проверить, был ли он вызван с определенным набором аргументов.

Это полезно. Предположим, вы хотите протестировать функцию, которая принимает список и вызывать другую функцию, compute(), для каждого из значений списка, только если они удовлетворяют конкретному условию.

Теперь вы можете mock compute и проверить, было ли оно вызвано каким-то значением, но не на других.

Ответ 6

С помощью python >= 3.5 вы можете использовать mock_object.assert_not_called().