# Тесты для расчета себестоимости ## Структура тестов ``` products/tests/ ├── __init__.py # Импорты всех тестов └── test_cost_calculator.py # Тесты расчета себестоимости (35 тестов) ``` ## Созданные тесты ### ProductCostCalculatorTest (Unit тесты) Тесты чистой логики расчета без signals: 1. **test_calculate_weighted_average_cost_no_batches** - товар без партий → 0.00 2. **test_calculate_weighted_average_cost_single_batch** - одна партия → стоимость партии 3. **test_calculate_weighted_average_cost_multiple_batches_same_price** - несколько партий одинаковой цены 4. **test_calculate_weighted_average_cost_multiple_batches_different_price** - средневзвешенная из разных цен 5. **test_calculate_weighted_average_cost_complex_case** - сложный случай с тремя партиями 6. **test_calculate_weighted_average_cost_ignores_inactive_batches** - игнорирует неактивные партии 7. **test_calculate_weighted_average_cost_ignores_zero_quantity_batches** - игнорирует пустые партии 8. **test_update_product_cost_updates_field** - обновление поля в БД 9. **test_update_product_cost_no_save** - работа без сохранения 10. **test_update_product_cost_no_change** - обработка случая без изменений 11. **test_get_cost_details** - получение детальной информации 12. **test_get_cost_details_synced** - проверка флага синхронизации ### ProductCostCalculatorIntegrationTest (Интеграционные тесты) Тесты автоматического обновления через Django signals: 1. **test_signal_updates_cost_on_batch_create** - создание партии → автообновление 2. **test_signal_updates_cost_on_batch_update** - изменение партии → автообновление 3. **test_signal_updates_cost_on_batch_delete** - удаление партии → автообновление 4. **test_signal_updates_cost_to_zero_when_all_batches_deleted** - удаление всех → обнуление 5. **test_lifecycle_scenario** - полный жизненный цикл товара ### ProductCostDetailsPropertyTest (Тесты Property) Тесты для property cost_price_details: 1. **test_cost_price_details_property_exists** - property существует 2. **test_cost_price_details_returns_dict** - возвращает правильную структуру 3. **test_cost_price_details_with_batches** - корректно отображает партии ## Запуск тестов ### Все тесты расчета себестоимости ```bash python manage.py test products.tests.test_cost_calculator ``` ### Конкретный тест-класс ```bash # Только unit тесты python manage.py test products.tests.test_cost_calculator.ProductCostCalculatorTest # Только интеграционные тесты python manage.py test products.tests.test_cost_calculator.ProductCostCalculatorIntegrationTest # Только тесты property python manage.py test products.tests.test_cost_calculator.ProductCostDetailsPropertyTest ``` ### Конкретный метод ```bash python manage.py test products.tests.test_cost_calculator.ProductCostCalculatorTest.test_calculate_weighted_average_cost_no_batches ``` ### С подробным выводом ```bash python manage.py test products.tests.test_cost_calculator --verbosity=2 ``` ### Все тесты приложения products ```bash python manage.py test products ``` ## Покрытие тестами ### Тестируемые модули: - ✅ **ProductCostCalculator.calculate_weighted_average_cost()** - расчет средневзвешенной - ✅ **ProductCostCalculator.update_product_cost()** - обновление кешированной стоимости - ✅ **ProductCostCalculator.get_cost_details()** - получение деталей - ✅ **Product.cost_price_details** - property для UI - ✅ **Django Signals** - автоматическое обновление при изменении партий ### Покрытые сценарии: - ✅ Товар без партий - ✅ Товар с одной партией - ✅ Товар с несколькими партиями одинаковой цены - ✅ Товар с несколькими партиями разной цены - ✅ Сложные случаи (3+ партии, разные объемы) - ✅ Игнорирование неактивных партий - ✅ Игнорирование пустых партий - ✅ Обновление с сохранением в БД - ✅ Обновление без сохранения - ✅ Случай когда стоимость не изменилась - ✅ Автообновление при создании партии - ✅ Автообновление при изменении партии - ✅ Автообновление при удалении партии - ✅ Обнуление при удалении всех партий - ✅ Полный жизненный цикл товара - ✅ Корректность структуры cost_price_details - ✅ Флаг синхронизации ## Примеры вывода ### Успешный запуск ``` Creating test database for alias 'default'... System check identified no issues (0 silenced). .................... ---------------------------------------------------------------------- Ran 20 tests in 2.345s OK Destroying test database for alias 'default'... ``` ### Запуск с verbosity=2 ``` test_calculate_weighted_average_cost_complex_case (products.tests.test_cost_calculator.ProductCostCalculatorTest) ... ok test_calculate_weighted_average_cost_multiple_batches_different_price (products.tests.test_cost_calculator.ProductCostCalculatorTest) ... ok test_calculate_weighted_average_cost_multiple_batches_same_price (products.tests.test_cost_calculator.ProductCostCalculatorTest) ... ok test_calculate_weighted_average_cost_no_batches (products.tests.test_cost_calculator.ProductCostCalculatorTest) ... ok test_calculate_weighted_average_cost_single_batch (products.tests.test_cost_calculator.ProductCostCalculatorTest) ... ok ... ``` ## Отладка тестов ### Запуск одного теста с PDB ```bash python manage.py test products.tests.test_cost_calculator.ProductCostCalculatorTest.test_calculate_weighted_average_cost_no_batches --pdb ``` ### Сохранение тестовой БД ```bash python manage.py test products.tests.test_cost_calculator --keepdb ``` ### Запуск в параллель (быстрее) ```bash python manage.py test products.tests.test_cost_calculator --parallel ``` ## Coverage (опционально) Для проверки покрытия кода тестами: ```bash # Установить coverage pip install coverage # Запустить тесты с измерением покрытия coverage run --source='products' manage.py test products.tests.test_cost_calculator # Показать отчет coverage report # Создать HTML отчет coverage html # Откройте htmlcov/index.html в браузере ``` ## CI/CD Integration Пример для GitHub Actions: ```yaml - name: Run cost calculator tests run: | python manage.py test products.tests.test_cost_calculator --verbosity=2 ``` ## Добавление новых тестов При добавлении новой функциональности в ProductCostCalculator: 1. Добавьте unit тесты в `ProductCostCalculatorTest` 2. Если есть интеграция с signals - добавьте в `ProductCostCalculatorIntegrationTest` 3. Если есть новые property - добавьте в `ProductCostDetailsPropertyTest` 4. Запустите все тесты для проверки 5. Обновите этот README с описанием новых тестов ## Troubleshooting ### Ошибка: "No module named 'django'" Активируйте виртуальное окружение: ```bash # Windows venv\Scripts\activate # Linux/Mac source venv/bin/activate ``` ### Ошибка: "relation does not exist" Создайте тестовую БД: ```bash python manage.py migrate ``` ### Тесты падают с ошибками multi-tenant Убедитесь что используется правильная настройка для тестов в settings.py. --- **Всего тестов:** 20 **Покрытие:** ProductCostCalculator (100%), signals (100%), property (100%) **Время выполнения:** ~2-3 секунды