Затвердити функцію / метод не викликали за допомогою Mock


131

Я використовую бібліотеку Mock для перевірки своєї програми, але хочу стверджувати, що деяка функція не викликалася. Фіктивні документи говорити про методи , як mock.assert_called_withі mock.assert_called_once_with, але я не знайшов нічого подібного mock.assert_not_calledабо було що - то пов'язано , щоб перевірити макет не називається .

Я міг би пойти з чимось на зразок наступного, хоча це не здається крутим і не пітонічним:

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's ok
    # other stuff

Будь-які ідеї, як це досягти?


Як вказує @Ahmet у своїй відповіді, assert_not_called тепер підтримується, також у зворотному порту ( docs.python.org/3/library/… ).
Мартін

Відповіді:


144

Це має працювати для вашого випадку;

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

Чи потрібна ця відповідь Джанго? Я отримую помилку:AttributeError: MockCallable instance has no attribute 'called'
Натан Артур

@NathanArthur Гм, я не думаю, що після, sudo easy_install -U mockі from mock import Mockна MacOS, вищезгадане працює без перешкод. Ніколи не встановлював Джанго :)
Йоахім Ісакссон

Хм. Це дивно. Я використовую Python 2.7.1 і використовую unittest та from mock import MockPython Mock 0.1.0 для моїх тестів. Чи щось із цього звучить проблематично?
Натан Артур

Я знущаюся над класом дзвінка з іншого модуля, так що це виглядає так module_to_test.another_module.class = mock.Mock(), чи можете ви підтвердити, що він не пам'ятає дзвінки в різних тестових випадках (unittest.TestCase)? Я думаю, що кількість викликів у цьому випадку не скидається
0xc0de

66

Хоча старе питання, я хотів би додати, що наразі mockбібліотека (backport unittest.mock) підтримує assert_not_calledметод.

Просто оновіть своє;

pip install mock --upgrade


29

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

self.assertItemsEqual(my_var.call_args_list, [])

Коли це не вдалося, воно видає таке повідомлення:

AssertionError: кількість елементів не дорівнювала:
Перший має 0, другий має 1: виклик ('перший аргумент', 4)

14

Під час тестування з використанням класу успадковується unittest.TestCase ви можете просто використовувати такі методи, як:

  • assrtTrue
  • assrtFalse
  • стверджувати, рівний

тощо (у документації на 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))

11

З python >= 3.5тобою можна користуватися mock_object.assert_not_called().


1

Судячи з інших відповідей, ніхто, окрім @ 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

Отже, спосіб вирішити конкретну проблему ОП - це

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

Зауважте, що таким чином, замість того, щоб просто перевірити, чи був викликаний глузливий дзвінок, через MagicMock.called, тепер ви можете перевірити, чи він викликався за допомогою певного набору аргументів.

Це корисно. Скажімо, ви хочете перевірити функцію, яка приймає список і викликати іншу функцію compute(), для кожного зі значень списку, лише якщо вони відповідають певній умові.

Тепер ви можете знущатись computeі перевіряти, чи було виклик якогось значення, а не іншого.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.