unisbadri.com » Python Java Golang Typescript Kotlin Ruby Rust Dart PHP
Mocking

Mocking #

Pengertian #

Mocking adalah teknik dalam pengujian perangkat lunak yang memungkinkan Anda menggantikan bagian dari kode dengan objek tiruan untuk mengisolasi unit yang diuji. Ini sangat berguna untuk menguji kode yang bergantung pada sumber daya eksternal seperti database, API, atau komponen lain yang mungkin sulit atau tidak praktis untuk diakses selama pengujian. Python menyediakan modul unittest.mock yang memudahkan pembuatan dan penggunaan mock.

Teknik-teknik Mocking #

  1. Mock Objects: Objek tiruan yang dapat digunakan untuk menggantikan objek nyata dalam pengujian.
  2. Patching: Teknik untuk mengganti objek nyata dengan mock selama pengujian.
  3. MagicMock: Subkelas dari Mock yang menyediakan metode tiruan tambahan dan lebih canggih.
  4. Side Effects: Cara untuk mengatur perilaku khusus ketika metode mock dipanggil.
  5. Assertions pada Mock: Memastikan bahwa metode tertentu telah dipanggil dengan argumen yang diharapkan.

Implementasi Mocking #

Mock Objects #

Mock adalah objek dasar yang dapat digunakan untuk menggantikan objek nyata.

from unittest.mock import Mock

# Membuat mock object
mock = Mock()

# Mengatur return value
mock.return_value = "Mocked!"

# Menggunakan mock object
result = mock()
print(result)  # Output: Mocked!

Patching #

patch digunakan untuk mengganti objek nyata dengan mock selama pengujian. Ini sering digunakan sebagai dekorator atau konteks manajer.

Contoh Patching sebagai Dekorator #

import unittest
from unittest.mock import patch

def fetch_data():
    import requests
    response = requests.get('http://example.com/data')
    return response.json()

class TestFetchData(unittest.TestCase):
    
    @patch('requests.get')
    def test_fetch_data(self, mock_get):
        # Mengatur return value dari mock
        mock_get.return_value.json.return_value = {'key': 'value'}
        
        result = fetch_data()
        
        # Memastikan bahwa hasilnya sesuai dengan yang diharapkan
        self.assertEqual(result, {'key': 'value'})

if __name__ == '__main__':
    unittest.main()

Contoh Patching sebagai Konteks Manajer #

import unittest
from unittest.mock import patch

def fetch_data():
    import requests
    response = requests.get('http://example.com/data')
    return response.json()

class TestFetchData(unittest.TestCase):
    
    def test_fetch_data(self):
        with patch('requests.get') as mock_get:
            # Mengatur return value dari mock
            mock_get.return_value.json.return_value = {'key': 'value'}
            
            result = fetch_data()
            
            # Memastikan bahwa hasilnya sesuai dengan yang diharapkan
            self.assertEqual(result, {'key': 'value'})

if __name__ == '__main__':
    unittest.main()

MagicMock #

MagicMock adalah subkelas dari Mock yang menyediakan metode tiruan tambahan seperti __call__, __len__, __iter__, dan lainnya.

from unittest.mock import MagicMock

# Membuat magic mock object
mock = MagicMock()

# Menggunakan magic mock object
mock.__len__.return_value = 5

print(len(mock))  # Output: 5

Side Effects #

side_effect memungkinkan Anda mengatur perilaku khusus ketika metode mock dipanggil, seperti melemparkan pengecualian atau mengembalikan nilai berbeda untuk setiap pemanggilan.

from unittest.mock import Mock

# Membuat mock object dengan side effect
mock = Mock(side_effect=[1, 2, 3])

print(mock())  # Output: 1
print(mock())  # Output: 2
print(mock())  # Output: 3

# Mengatur side effect untuk melemparkan pengecualian
mock.side_effect = Exception("Error!")
try:
    mock()
except Exception as e:
    print(e)  # Output: Error!

Assertions #

Anda dapat memastikan bahwa metode tertentu telah dipanggil dengan argumen yang diharapkan menggunakan metode assertion yang disediakan oleh Mock.

from unittest.mock import Mock

# Membuat mock object
mock = Mock()

# Menggunakan mock object
mock.method("arg1", "arg2")

# Memastikan bahwa metode dipanggil dengan argumen yang benar
mock.method.assert_called_with("arg1", "arg2")

# Memastikan bahwa metode dipanggil sekali
mock.method.assert_called_once()

# Memastikan bahwa metode dipanggil dua kali
mock.method("arg1", "arg2")
mock.method.assert_called_with("arg1", "arg2")
mock.method.assert_called_once_with("arg1", "arg2")
mock.method.call_count  # Output: 2

Contoh Penggunaan Mocking #

Misalkan kita memiliki fungsi yang memeriksa ketersediaan produk dari layanan eksternal dan mengirim email notifikasi jika produk tersedia.

# Modul yang akan diuji
import requests

def check_product_availability(product_id):
    response = requests.get(f'http://api.example.com/products/{product_id}')
    if response.json().get('available'):
        send_email_notification(product_id)

def send_email_notification(product_id):
    print(f"Product {product_id} is available. Sending email notification.")

Kita ingin menguji fungsi check_product_availability tanpa benar-benar melakukan permintaan HTTP dan mengirim email.

import unittest
from unittest.mock import patch, call

class TestProductAvailability(unittest.TestCase):
    
    @patch('requests.get')
    @patch('__main__.send_email_notification')
    def test_check_product_availability(self, mock_send_email, mock_get):
        # Mengatur return value dari mock
        mock_get.return_value.json.return_value = {'available': True}
        
        # Memanggil fungsi yang akan diuji
        check_product_availability(1)
        
        # Memastikan bahwa permintaan HTTP dilakukan dengan URL yang benar
        mock_get.assert_called_with('http://api.example.com/products/1')
        
        # Memastikan bahwa email notifikasi dikirim
        mock_send_email.assert_called_once_with(1)
    
    @patch('requests.get')
    @patch('__main__.send_email_notification')
    def test_check_product_not_available(self, mock_send_email, mock_get):
        # Mengatur return value dari mock
        mock_get.return_value.json.return_value = {'available': False}
        
        # Memanggil fungsi yang akan diuji
        check_product_availability(1)
        
        # Memastikan bahwa permintaan HTTP dilakukan dengan URL yang benar
        mock_get.assert_called_with('http://api.example.com/products/1')
        
        # Memastikan bahwa email notifikasi tidak dikirim
        mock_send_email.assert_not_called()

if __name__ == '__main__':
    unittest.main()

Kesimpulan #

Mocking adalah teknik penting dalam pengujian perangkat lunak yang memungkinkan Anda untuk menggantikan bagian dari kode dengan objek tiruan, sehingga Anda dapat mengisolasi unit yang diuji. Python menyediakan modul unittest.mock yang memudahkan pembuatan dan penggunaan mock. Dengan menggunakan mock objects, patching, MagicMock, side effects, dan assertions pada mock, Anda dapat menulis tes yang lebih robust dan memastikan bahwa kode Anda berfungsi sebagaimana mestinya dalam berbagai skenario.

« Unit Test
JSON »