Что такое модульное тестирование (Unit Testing)?

«Что такое модульное тестирование (Unit Testing)?» — вопрос из категории Основы тестирования, который задают на 10% собеседований QA Тестировщик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Модульное тестирование (Unit Testing) — это уровень тестирования, направленный на проверку корректности работы наименьших изолируемых частей программы (юнитов) — обычно функций, методов или классов — в отрыве от остальной системы и внешних зависимостей (баз данных, сетевых запросов, файловой системы).

Ключевые принципы и характеристики:

  • Изоляция: Юнит-тест должен проверять только логику одного модуля. Внешние зависимости заменяются заглушками (stubs) или имитаторами (mocks).
  • Скорость: Юнит-тесты должны выполняться очень быстро (миллисекунды), чтобы их можно было запускать часто.
  • Детерминированность: Результат теста всегда одинаков для одних и тех же входных данных.
  • Автоматизация: Тесты пишутся в коде и запускаются автоматически (часто в CI/CD).

Пример модульного теста с использованием фреймворка pytest и моков (unittest.mock):

# Файл: calculator.py
class Calculator:
    def add(self, a, b):
        return a + b

# Файл: service.py
class DataService:
    def fetch_external_data(self):
        # Дорогой или нестабильный вызов внешнего API
        return 42

class ProcessingService:
    def __init__(self, calculator, data_service):
        self.calc = calculator
        self.data_svc = data_service

    def process(self, x, y):
        external_value = self.data_svc.fetch_external_data()
        return self.calc.add(x, y) + external_value

# Файл: test_processing_service.py
import pytest
from unittest.mock import Mock
from service import ProcessingService
from calculator import Calculator

def test_process_with_mocks():
    # 1. Создаем мок-объекты для зависимостей
    mock_calculator = Mock(spec=Calculator)
    mock_data_service = Mock()

    # 2. Настраиваем поведение моков
    mock_calculator.add.return_value = 10  # Мок метода add
    mock_data_service.fetch_external_data.return_value = 5  # Мок внешнего вызова

    # 3. Создаем тестируемый объект, передавая моки
    service = ProcessingService(mock_calculator, mock_data_service)

    # 4. Выполняем тестируемый метод
    result = service.process(3, 7)

    # 5. Проверяем результат и взаимодействие с моками (assertions)
    assert result == 15  # 10 (от мока калькулятора) + 5 (от мока сервиса данных)
    mock_calculator.add.assert_called_once_with(3, 7)  # Проверяем, что add вызван с правильными аргументами
    mock_data_service.fetch_external_data.assert_called_once()  # Проверяем, что метод вызван

Популярные фреймворки для модульного тестирования:

  • Python: pytest, unittest
  • JavaScript/TypeScript: Jest, Mocha + Chai
  • Java: JUnit, TestNG
  • C#: NUnit, xUnit.net, MSTest