Перейти до змісту

Testing mock and monkeypatch

Мокування (Mocking)

Mock-об'єкт замінює та імітує реальний об'єкт під час тесту. Це гнучкий і потужний інструмент для покращення якості ваших тестів.

MagicMock

unittest.mock — це бібліотека для мокування в Python. Вона надає простий спосіб впровадження mock-об'єктів у ваші тести. Наприклад, файл main.py:

import time


def delay(seconds: int, func):
    time.sleep(seconds)
    return func()

Файл test_main.py:

from unittest import mock

from main import delay


def test_function_has_called():
    mock_function = mock.MagicMock()
    delay(3, mock_function)
    mock_function.assert_called_once()

Мокування з mock.patch з Unittest

unittest.mock надає потужний інструмент для мокування об'єктів — patch(), який знаходить об'єкт у заданому модулі та замінює цей об'єкт mock-об'єктом.

Зазвичай ми використовуємо patch() як декоратор або контекстний менеджер для надання області, в якій можна мокувати цільовий об'єкт.

Якщо ви хочете мокувати об'єкт протягом всієї тестової функції, ви можете використовувати patch() як декоратор функції.

Приклад використання patch():

# test_main.py
from unittest import mock

from main import delay


@mock.patch("time.sleep")
def test_function_has_called(mocked_sleep):
    delay(100, lambda: None)
    mocked_sleep.assert_called_once_with(100)

Мокування з контекстним менеджером

Іноді вам потрібно використовувати patch() як контекстний менеджер, а не декоратор, наприклад, коли:

ви хочете мокувати об'єкт лише для частини тестової області; ви вже використовуєте занадто багато декораторів або параметрів, що погіршує читабельність тесту.

Наприклад:

from unittest import mock

from main import delay


def test_function_has_called():
    with mock.patch("time.sleep") as mocked_sleep:
        delay(100, lambda: None)
        mocked_sleep.assert_called_once_with(100)

Pytest Monkeypatch

pytest також надає механізм мокування — monkeypatch, який є аналогом unittest.mock. Наприклад, файл main.py:

import os


def get_current_path():
    current_path = os.getcwd()
    return current_path  # Повертає поточну директорію

Файл test_main.py:

import os

from main import get_current_path


def test_get_current_directory(monkeypatch):

    def mock_getcwd():
        return '/data/user/directory123'

    monkeypatch.setattr(os, 'getcwd', mock_getcwd)  # Мокування результату os.getcwd()
    assert get_current_path() == '/data/user/directory123'