Pengantar
Artikel ini memberikan pengenalan rinci tentang penggunaan patch
dalam unittest Python.
patch
Metode patch()
unittest Python membuat objek tiruan dan menukar referensi ke objek tujuan tambalan yang ditentukan. Argumen utamanya adalah sebagai berikut.
Argumen | Deskripsi |
---|---|
target |
Objek yang akan ditambal. Tentukan nama modul dalam format string atau tentukan objek itu sendiri. |
new |
Objek yang akan diganti dengan target . Opsional. |
side_effect |
Fungsi yang mendefinisikan pengecualian yang akan dimunculkan ketika mock dipanggil, nilai yang akan dikembalikan, atau objek yang dapat dipanggil. Opsional. |
return_value |
Nilai yang dikembalikan ketika mock dipanggil. Opsional. |
autospec |
Jika True , memastikan bahwa objek new dengan benar memenuhi spesifikasi objek target . |
spec |
Jika True , memastikan bahwa objek new dengan benar memenuhi spesifikasi objek target . |
create |
Nilai boolean yang menentukan apakah akan secara otomatis membuat atribut untuk panggilan tiruan. Opsional, nilai defaultnya adalah False . |
new_callable |
ika new bukan objek yang dapat dipanggil, tentukan objek yang dapat dipanggil untuk membuat objek yang dapat dipanggil. |
unsafe |
Jika target penambalan adalah sebuah modul, nilai False akan menyebabkan verifikasi dilakukan. Opsional; nilai standarnya adalah True . |
new
Argumen new
pada metode patch
dapat digunakan untuk mengganti objek asli sepenuhnya. Argumen ini dapat digunakan untuk membuat objek baru yang lengkap sebagai objek tiruan. Berikut ini adalah contoh penggantian objek Foo
menggunakan argumen new
.
from unittest.mock import patch
class Foo:
def bar(self):
return "original"
with patch('__main__.Foo', new=lambda: "mock"):
f = Foo()
assert f.bar() == "mock"
Dalam contoh ini, pemanggilan metode bar()
pada sebuah instance dari kelas Foo
mengembalikan "mock"
. Artinya, objek asli digantikan oleh objek tiruan.
Hal ini juga memungkinkan untuk menetapkan nilai dummy ke variabel global.
from unittest.mock import patch
def test_my_global_variable():
with patch('my_module.my_global_variable', new='dummy'):
assert my_module.my_global_variable == 'dummy'
Pada contoh ini, my_module.my_global_variable
diganti dengan string 'dummy'
. Argumen new
menetapkan nilai baru yang diberikan untuk variabel global.
return_value
Argumen return_value
dapat digunakan untuk menentukan nilai yang akan dikembalikan ketika mock dipanggil. Contoh berikut ini membuat mock yang mengembalikan nilai yang ditentukan oleh return_value
ketika my_function
dipanggil.
from unittest.mock import patch
def my_function():
return 42
with patch('__main__.my_function', return_value=84):
result = my_function()
print(result) # 84
wraps
Argumen wraps
memungkinkan mock untuk meniru perilaku objek yang dibungkusnya. Artinya, mock akan memiliki atribut dan metode objek yang dibungkusnya. Contoh berikut ini membuat mock yang menjalankan my_function
asli ketika my_function
dipanggil.
from unittest.mock import patch
def my_function():
return 42
with patch('__main__.my_function', wraps=my_function):
result = my_function()
print(result) # 42
side_effect
Argumen side_effect
dapat digunakan untuk menentukan pengecualian yang akan dimunculkan ketika mock dipanggil. Contoh berikut ini membuat mock yang memunculkan ValueError
ketika my_function
dipanggil.
from unittest.mock import patch
def my_function():
return 42
with patch('__main__.my_function', side_effect=ValueError('oops')):
result = my_function()
print(result) # ValueError: oops
patch.object
patch.object()
adalah metode dari unittest.mock
yang digunakan untuk mengganti atribut objek yang diberikan dengan objek tiruan. Metode ini dapat digunakan untuk mengganti atribut objek apa pun dalam modul, seperti atribut instance kelas atau variabel global. Hal ini memungkinkan Anda untuk mengonfigurasi pengujian agar berjalan pada kondisi tertentu.
Sintaks dari patch.object()
adalah sebagai berikut.
patch.object(target, attribute, new=DEFAULT, **kwargs)
Argumen | Deskripsi |
---|---|
target |
Tentukan objek yang akan ditambal. |
attribute |
Tentukan nama atribut yang akan ditambal. |
new |
Menentukan nilai baru untuk objek. Nilai default adalah DEFAULT , yang secara otomatis membuat objek tiruan. |
**kwargs |
Digunakan untuk menentukan argumen penambalan tambahan. |
Berikut ini adalah contoh penggunaan patch.object()
.
from unittest.mock import patch
class MyClass:
def __init__(self):
self.x = 10
def my_function():
obj = MyClass()
return obj.x
with patch.object(MyClass, 'x', 20):
assert my_function() == 20
Pada contoh ini, atribut instance x
dari MyClass
ditambal dan disetel ke 20
. Karena my_function()
membuat sebuah instance dari MyClass
dan mengembalikan x
, maka nilai kembalian dari my_function()
adalah 20
.
Contoh lain dari patch.object
meliputi
- Mengganti metode dari sebuah objek
from unittest.mock import patch
class MyClass:
def my_method(self):
return "original"
with patch.object(MyClass, "my_method", return_value="mocked"):
obj = MyClass()
result = obj.my_method()
print(result) # => "mocked"
- Mengganti atribut modul
from unittest.mock import patch
import my_module
with patch.object(my_module, "my_function", return_value="mocked"):
result = my_module.my_function()
print(result) # => "mocked"
- Mengajukan Pengecualian
from unittest.mock import patch
def my_function():
raise ValueError("original")
with patch.object(__main__, "my_function", side_effect=RuntimeError("mocked")):
with pytest.raises(RuntimeError, match="mocked"):
my_function()
Perbedaan dari patch
Baik patch
maupun patch.object
adalah metode dari unitest.mock
untuk membuat dan mengkonfigurasi mock, namun ada perbedaan dalam penggunaannya.
patch
mengambil jalur string atau objek sebagai argumen yang menentukan objek yang akan ditiru. Jika objek yang akan ditiru adalah metode kelas, ia akan meniru nama kelas dalam string yang dioper sebagai argumen pertama dan menggantinya dengan objek tiruan. Selain itu, patch
dimaksudkan untuk digunakan dalam pernyataan with
.
Di sisi lain, patch.object
mengambil objek yang akan ditiru dan sebuah string yang menentukan atribut objek sebagai argumen. Meskipun objek yang akan ditiru adalah metode kelas, objek yang dilewatkan sebagai argumen pertama akan ditiru dan digunakan untuk mengganti atributnya. patch.object
tidak perlu digunakan dalam pernyataan with
.
Dengan demikian, Anda dapat menggunakan patch.object
untuk meniru atribut tertentu dari sebuah objek, tetapi Anda dapat menggunakan patch
untuk meniru seluruh objek.
Sebagai contoh, misalkan Anda memiliki kode berikut ini.
class MyClass:
def my_method(self):
return 'real'
my_instance = MyClass()
You can mock an entire MyClass
using patch
as follows
from unittest.mock import patch
with patch('my_module.MyClass') as MockClass:
instance = MockClass.return_value
instance.my_method.return_value = 'mocked'
assert my_instance.my_method() == 'mocked'
On the other hand, you can mock only the my_method
attribute of MyClass
using patch.object
as follows.
from unittest.mock import patch
with patch.object(my_instance, 'my_method') as mock_method:
mock_method.return_value = 'mocked'
assert my_instance.my_method() == 'mocked'
Dekorator dan pernyataan with
Pada patch
unittest Python, menggunakan dekorator dan pernyataan with
pada dasarnya memiliki efek yang sama, tetapi ada perbedaan dalam cara penulisannya.
Ketika menggunakan dekorator, Anda dapat mengaktifkan mocking untuk semua metode pengujian dalam kasus pengujian. Berikut ini adalah contoh penggunaan dekorator.
import unittest
from unittest.mock import patch
class MyTestCase(unittest.TestCase):
@patch('mymodule.some_function')
def test_my_function(self, mock_some_function):
# test ode with mocked function
Jika Anda menggunakan pernyataan with
, Anda dapat mengaktifkan mocking hanya di dalam pernyataan with
. Berikut ini adalah contoh penggunaan pernyataan with
.
import unittest
from unittest.mock import patch
class MyTestCase(unittest.TestCase):
def test_my_function(self):
with patch('mymodule.some_function') as mock_some_function:
# test code with mocked function
Secara umum, menggunakan dekorator membuat kode tetap ringkas. Namun, jika Anda perlu menyesuaikan mock untuk setiap metode pengujian, Anda dapat menggunakan pernyataan with
. Selain itu, ketika menggunakan pernyataan with
, mock secara otomatis dibersihkan di akhir blok with
, jadi jika ada yang gagal selama pengujian, pembersihan akan tetap terjadi.
Mendefinisikan beberapa patch
Contoh pendefinisian beberapa patch ditunjukkan di bawah ini.
Sebagai contoh, misalkan Anda memiliki modul berikut ini.
import os
def my_function():
return os.path.abspath(__file__)
Untuk mendefinisikan beberapa patch untuk modul ini, lakukan hal berikut.
import unittest.mock
import my_module
class TestMyModule(unittest.TestCase):
def test_my_function(self):
with unittest.mock.patch('my_module.os'):
with unittest.mock.patch('my_module.os.path.abspath') as abspath_mock:
abspath_mock.return_value = 'my/absolute/path'
result = my_module.my_function()
self.assertEqual(result, 'my/absolute/path')
Pada contoh ini, patch diterapkan pada modul os
dan fungsi path.abspath
. Untuk menerapkan patch, gunakan metode unittest.mock.patch()
, dengan jalur objek yang ingin Anda terapkan patch sebagai argumen. Untuk menerapkan beberapa patch, gunakan pernyataan with
bersarang. Objek tambalan juga dapat di-alias menggunakan klausa as
. Di sini kita memiliki alias abspath_mock
dan menggunakan atribut return_value
untuk mengatur nilai balik dari mock.
Untuk mendefinisikan beberapa dekorator patch
, gunakan yang berikut ini.
from unittest.mock import patch
@patch('module1.function1')
@patch('module2.function2')
def test_my_function(mock_function2, mock_function1):
# test code
pass
Pada contoh ini, dua dekorator patch
digunakan untuk menambal module1.function1
dan module2.function2
. Dalam kasus ini, harus diperhatikan untuk memastikan bahwa urutan argumen fungsi uji sesuai dengan urutan dekorator. Artinya, mock_function1
adalah tiruan dari module1.function1
dan mock_function2
adalah tiruan dari module2.function2
.
Referensi