Traffine I/O

Bahasa Indonesia

2023-02-17

unittest patch

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.

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

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

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

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

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

python
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().

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

python
class MyClass:
    def my_method(self):
        return 'real'

my_instance = MyClass()

You can mock an entire MyClass using patch as follows

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

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

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

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

my_module.py

import os

def my_function():
    return os.path.abspath(__file__)

Untuk mendefinisikan beberapa patch untuk modul ini, lakukan hal berikut.

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

python
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

https://docs.python.org/3/library/unittest.mock.html#the-patchers

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!