Bagaimana Anda mengejek properti hanya-baca dengan tiruan ?
Saya mencoba:
setattr(obj.__class__, 'property_to_be_mocked', mock.Mock())
tapi masalahnya adalah itu kemudian berlaku untuk semua contoh kelas ... yang merusak tes saya.
Apakah Anda punya ide lain? Saya tidak ingin mengejek objek penuh, hanya properti khusus ini.
python
unit-testing
mocking
pytest
charlax.dll
sumber
sumber
@property
. Jawaban ini berhasil bagi saya ketika jawaban lain (dan jawaban lain untuk banyak pertanyaan lain) tidak.Sebenarnya jawabannya adalah (seperti biasa) di dokumentasi , hanya saja saya menerapkan patch ke instance bukan class ketika saya mengikuti contoh mereka.
Berikut cara melakukannya:
class MyClass: @property def last_transaction(self): # an expensive and complicated DB query here pass
Di rangkaian pengujian:
def test(): # Make sure you patch on MyClass, not on a MyClass instance, otherwise # you'll get an AttributeError, because mock is using settattr and # last_transaction is a readonly property so there's no setter. with mock.patch(MyClass, 'last_transaction') as mock_last_transaction: mock_last_transaction.__get__ = mock.Mock(return_value=Transaction()) myclass = MyClass() print myclass.last_transaction
sumber
mock.PropertyMock
adalah cara untuk melakukannya!PropertyMock
tidak ada.Jika objek yang propertinya ingin Anda timpa adalah objek tiruan, Anda tidak perlu menggunakan
patch
.Sebagai gantinya, dapat membuat
PropertyMock
dan menimpa properti pada tipe tiruan. Misalnya, untuk menggantimock_rows.pages
properti yang akan dikembalikan(mock_page, mock_page,)
:mock_page = mock.create_autospec(reader.ReadRowsPage) # TODO: set up mock_page. mock_pages = mock.PropertyMock(return_value=(mock_page, mock_page,)) type(mock_rows).pages = mock_pages
sumber
Mungkin masalah gaya, tetapi jika Anda lebih suka dekorator dalam tes, jawaban @jamescastlefield dapat diubah menjadi seperti ini:
class MyClass: @property def last_transaction(self): # an expensive and complicated DB query here pass class Test(unittest.TestCase): @mock.patch('MyClass.last_transaction', new_callable=PropertyMock) def test(self, mock_last_transaction): mock_last_transaction.return_value = Transaction() myclass = MyClass() print myclass.last_transaction mock_last_transaction.assert_called_once_with()
sumber
Jika Anda menggunakan
pytest
bersama denganpytest-mock
, Anda dapat menyederhanakan kode Anda dan juga menghindari menggunakan palungan konteks, yaituwith
pernyataan sebagai berikut:def test_name(mocker): # mocker is a fixture included in pytest-mock mocked_property = mocker.patch( 'MyClass.property_to_be_mocked', new_callable=mocker.PropertyMock, return_value='any desired value' ) o = MyClass() print(o.property_to_be_mocked) # this will print: any desired value mocked_property.assert_called_once_with()
sumber
Jika Anda tidak ingin menguji apakah properti tiruan telah diakses atau tidak, Anda cukup menambalnya dengan yang diharapkan
return_value
.with mock.patch(MyClass, 'last_transaction', Transaction()): ...
sumber
Jika Anda membutuhkan ejekan Anda
@property
untuk mengandalkan yang asli__get__
, Anda dapat membuat kebiasaan AndaMockProperty
class PropertyMock(mock.Mock): def __get__(self, obj, obj_type=None): return self(obj, obj_type)
Pemakaian:
class A: @property def f(self): return 123 original_get = A.f.__get__ def new_get(self, obj_type=None): return f'mocked result: {original_get(self, obj_type)}' with mock.patch('__main__.A.f', new_callable=PropertyMock) as mock_foo: mock_foo.side_effect = new_get print(A().f) # mocked result: 123 print(mock_foo.call_count) # 1
sumber