Mock kullanılarak bir işlev / yöntem çağrılmadığını iddia et


131

Uygulamamı test etmek için Mock kitaplığını kullanıyorum, ancak bazı işlevlerin çağrılmadığını iddia etmek istiyorum. Sahte belgeler gibi yöntemleri hakkında konuşmak mock.assert_called_withve mock.assert_called_once_withama böyle bir şey bulamadık mock.assert_not_calledalay doğrulamak için ilgili bir şey oldu ya adlandırılan DEĞİL .

Havalı ya da pitonik görünmese de aşağıdaki gibi bir şeyle gidebilirim:

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

Bunu nasıl başaracağınıza dair bir fikriniz var mı?


@Ahmet'in yanıtında belirttiği gibi, assert_not_called artık arka portta da destekleniyor ( docs.python.org/3/library/… ).
Martin

Yanıtlar:


144

Bu sizin durumunuz için çalışmalıdır;

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

Örneklem;

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

Bu cevap Django gerektiriyor mu? Bir hata alıyorum:AttributeError: MockCallable instance has no attribute 'called'
Nathan Arthur

@NathanArthur Hm, sanmıyorum, MacOS'tan sonra sudo easy_install -U mockve sonra from mock import Mock, yukarıdaki işlemler sorunsuz çalışıyor. Hiç Django yüklenmedi :)
Joachim Isaksson

Hmm. Bu garip. Python 2.7.1 çalıştırıyorum ve from mock import Mocktestlerim için unittest ve Python Mock 0.1.0 kullanıyorum . Bunlardan herhangi biri sorunlu mu?
Nathan Arthur

Başka bir modülden çağrılabilir bir sınıfla alay ediyorum, öyle görünüyor ki, bunun module_to_test.another_module.class = mock.Mock()farklı test durumlarındaki (unittest.TestCase örnekleri) çağrıları hatırlamadığını onaylayabilir misiniz? Bu durumda çağrı sayısının sıfırlanmadığını düşünüyorum
0xc0de

67

Eski bir soru olmasına rağmen, şu anda mockkütüphanenin (unittest.mock backport) assert_not_calledyöntemi desteklediğini eklemek istiyorum .

Sadece sizinkini yükseltin;

pip install mock --upgrade


29

calledÖzniteliği kontrol edebilirsiniz , ancak iddianız başarısız olursa, bilmek isteyeceğiniz bir sonraki şey beklenmedik çağrı hakkında bir şeydir , bu nedenle bu bilgilerin en baştan görüntülenmesini de ayarlayabilirsiniz. Kullanarak bunun yerine unittestiçeriğini kontrol edebilirsiniz call_args_list:

self.assertItemsEqual(my_var.call_args_list, [])

Başarısız olduğunda şöyle bir mesaj verir:

AssertionError: Öğe sayıları eşit değildi:
İlkinde 0, İkincide 1: call ('ilk bağımsız değişken', 4)

14

Sınıfı devralır unittest.TestCase kullanarak test yaptığınızda, aşağıdaki gibi yöntemleri kullanabilirsiniz:

  • assertTrue
  • assertFalse
  • assertEqual

ve benzer ( python belgelerinde gerisini bulursunuz).

Örneğinizde mock_method.called özelliğinin False olup olmadığını basitçe söyleyebiliriz , bu da bu yöntemin çağrılmadığı anlamına gelir.

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

İle python >= 3.5kullanabilirsiniz mock_object.assert_not_called().


1

Diğer cevaplar bakılırsa, dışında hiç kimse soymak-Kennedy @ bahsettik call_args_list.

Tam tersini uygulayabileceğiniz güçlü bir araçtır. MagicMock.assert_called_with()

call_args_listcallnesnelerin bir listesidir . Her callnesne, sahte bir çağrılabilir üzerinde yapılan bir çağrıyı temsil eder.

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

Bir callnesneyi tüketmek kolaydır, çünkü onu birinci bileşenin ilgili çağrının tüm konumsal argümanlarını içeren bir demet olduğu, ikinci bileşenin ise anahtar kelime argümanlarının bir sözlüğü olduğu 2 uzunluğundaki bir demet ile karşılaştırabilirsiniz.

>>> ((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

Öyleyse, OP'nin özel sorununu ele almanın bir yolu,

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

Bu şekilde, sadece sahte bir çağrılabilirin çağrılıp çağrılmadığını kontrol etmek yerine MagicMock.called, şimdi belirli bir argüman kümesiyle çağrılıp çağrılmadığını kontrol edebilirsiniz.

Bu yararlıdır. Listenin compute()her bir değeri için, yalnızca belirli bir koşulu karşıladıklarında , bir listeyi alan ve başka bir işlevi çağıran bir işlevi test etmek istediğinizi varsayalım.

Şimdi alay edebilir computeve bir değer için çağrılıp diğerlerinde çağrılmadığını test edebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.