251 lines
12 KiB
Python
251 lines
12 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
Объединенный класс тестов для проекта KadastrParser
|
||
"""
|
||
|
||
import os
|
||
import tempfile
|
||
from pathlib import Path
|
||
import unittest
|
||
from typing import Optional
|
||
|
||
# Импорт наших модулей
|
||
from models.cadastral_record import CadastralRecord
|
||
from models.xml_file_info import XMLFileInfo
|
||
from services.file_seeker import FileSeeker
|
||
from services.excel_processor import ExcelProcessor
|
||
|
||
|
||
class KadastrParserTests(unittest.TestCase):
|
||
"""Объединенный класс тестов для всех компонентов системы"""
|
||
|
||
@classmethod
|
||
def setUpClass(cls):
|
||
"""Настройка тестовой среды"""
|
||
cls.test_xml_dir = r"c:\Users\USER\Downloads\14. выборка выписок из ЕГРН по списку КН\пример исх.папки 2 вар"
|
||
cls.test_excel_file = r"c:\Users\USER\Downloads\14. выборка выписок из ЕГРН по списку КН\список КН.xlsx"
|
||
cls.test_xml_file = r"c:\Users\USER\Downloads\14. выборка выписок из ЕГРН по списку КН\пример исх.папки 2 вар\report-1a3f8d46-0b14-4ae3-ac2e-f10372020fed-PKPVD-2025-05-12-224487-74-01[0].xml"
|
||
|
||
# Создаем временную директорию для результатов
|
||
cls.temp_dir = Path("test_results")
|
||
cls.temp_dir.mkdir(exist_ok=True)
|
||
|
||
def test_01_module_imports(self):
|
||
"""Тестирует импорт и создание всех модулей"""
|
||
print("\n=== ТЕСТ 1: ИМПОРТ МОДУЛЕЙ ===")
|
||
|
||
# Тест создания CadastralRecord
|
||
record = CadastralRecord("74:34:0400003:1234", "test.xml", {"74:34:0400003:1234", "74:34:0400003:5678"})
|
||
self.assertEqual(record.main_number, "74:34:0400003:1234")
|
||
self.assertEqual(record.file_path, "test.xml")
|
||
self.assertEqual(len(record.all_numbers), 2)
|
||
self.assertEqual(len(record.other_numbers), 1)
|
||
print(f" ✅ CadastralRecord: {record}")
|
||
|
||
# Тест создания FileSeeker
|
||
temp_dir = tempfile.mkdtemp()
|
||
seeker = FileSeeker(temp_dir)
|
||
stats = seeker.get_statistics()
|
||
self.assertIsInstance(stats, dict)
|
||
print(f" ✅ FileSeeker создан: {seeker}")
|
||
|
||
# Тест создания ExcelProcessor
|
||
excel_processor = ExcelProcessor("dummy.xlsx")
|
||
self.assertIsInstance(excel_processor, ExcelProcessor)
|
||
print(f" ✅ ExcelProcessor создан")
|
||
|
||
def test_02_single_xml_file_extraction(self):
|
||
"""Тестирует извлечение из одного XML файла"""
|
||
print("\n=== ТЕСТ 2: ИЗВЛЕЧЕНИЕ ИЗ XML ФАЙЛА ===")
|
||
|
||
if not os.path.exists(self.test_xml_file):
|
||
self.skipTest(f"Тестовый файл не найден: {self.test_xml_file}")
|
||
|
||
xml_info = XMLFileInfo(self.test_xml_file)
|
||
main_number, all_numbers = xml_info.extract_cadastral_data()
|
||
|
||
self.assertIsNotNone(main_number)
|
||
self.assertGreater(len(all_numbers), 0)
|
||
self.assertIn(main_number, all_numbers)
|
||
|
||
print(f" 📋 Основной номер: {main_number}")
|
||
print(f" 📋 Всего номеров: {len(all_numbers)}")
|
||
print(f" 📋 Номера: {sorted(all_numbers)}")
|
||
|
||
def test_03_directory_processing(self):
|
||
"""Тестирует обработку директории с XML файлами"""
|
||
print("\n=== ТЕСТ 3: ОБРАБОТКА ДИРЕКТОРИИ ===")
|
||
|
||
if not os.path.exists(self.test_xml_dir):
|
||
self.skipTest(f"Тестовая директория не найдена: {self.test_xml_dir}")
|
||
|
||
seeker = FileSeeker(self.test_xml_dir, str(self.temp_dir))
|
||
|
||
# Поиск файлов
|
||
xml_files = seeker.find_xml_files()
|
||
self.assertGreater(len(xml_files), 0)
|
||
print(f" 📁 Найдено XML файлов: {len(xml_files)}")
|
||
|
||
# Обработка файлов (новая реализация с объектами)
|
||
records = seeker.process_files()
|
||
self.assertGreater(len(records), 0)
|
||
print(f" 📋 Создано объектов: {len(records)}")
|
||
|
||
# Проверяем статистику
|
||
stats = seeker.get_statistics()
|
||
self.assertEqual(stats['total_xml_files'], len(xml_files))
|
||
self.assertEqual(stats['total_cadastral_objects'], len(records))
|
||
|
||
print(f" 📊 Статистика:")
|
||
for key, value in stats.items():
|
||
print(f" • {key}: {value}")
|
||
|
||
# Проверяем первые несколько записей
|
||
print(f" 📋 Первые 3 объекта:")
|
||
for i, record in enumerate(records[:3]):
|
||
print(f" {i+1}. Основной: {record.main_number}")
|
||
print(f" Все номера: {sorted(record.all_numbers)}")
|
||
print(f" Других номеров: {len(record.other_numbers)}")
|
||
|
||
def test_04_excel_processing(self):
|
||
"""Тестирует обработку Excel файла"""
|
||
print("\n=== ТЕСТ 4: ОБРАБОТКА EXCEL ===")
|
||
|
||
if not os.path.exists(self.test_excel_file):
|
||
self.skipTest(f"Excel файл не найден: {self.test_excel_file}")
|
||
|
||
excel_processor = ExcelProcessor(self.test_excel_file)
|
||
success = excel_processor.load_excel_file()
|
||
self.assertTrue(success)
|
||
|
||
excel_numbers = excel_processor.get_cadastral_numbers()
|
||
self.assertGreater(len(excel_numbers), 0)
|
||
print(f" 📊 Номеров в Excel: {len(excel_numbers)}")
|
||
|
||
# Показываем первые 5 номеров
|
||
print(f" 📋 Первые 5 номеров из Excel:")
|
||
for i, number in enumerate(sorted(excel_numbers)[:5]):
|
||
print(f" {i+1}. {number}")
|
||
|
||
def test_05_full_integration(self):
|
||
"""Полный интеграционный тест XML + Excel + обновление"""
|
||
print("\n=== ТЕСТ 5: ПОЛНАЯ ИНТЕГРАЦИЯ ===")
|
||
|
||
if not os.path.exists(self.test_xml_dir) or not os.path.exists(self.test_excel_file):
|
||
self.skipTest("Тестовые файлы не найдены для интеграционного теста")
|
||
|
||
# 1. Обработка XML файлов
|
||
seeker = FileSeeker(self.test_xml_dir, str(self.temp_dir))
|
||
xml_files = seeker.find_xml_files()
|
||
records = seeker.process_files()
|
||
|
||
# 2. Обработка Excel файла
|
||
excel_processor = ExcelProcessor(self.test_excel_file)
|
||
excel_processor.load_excel_file()
|
||
excel_numbers = excel_processor.get_cadastral_numbers()
|
||
|
||
# 3. Поиск совпадений (по всем номерам в объектах)
|
||
all_xml_numbers = seeker.get_all_cadastral_numbers()
|
||
matching_numbers = excel_numbers.intersection(all_xml_numbers)
|
||
|
||
print(f" 🏷️ XML номеров (всего): {len(all_xml_numbers)}")
|
||
print(f" 📊 Excel номеров: {len(excel_numbers)}")
|
||
print(f" 🎯 Совпадений: {len(matching_numbers)}")
|
||
|
||
self.assertGreater(len(matching_numbers), 0, "Должны быть найдены совпадения")
|
||
|
||
# 4. Тестируем новый метод обновления Excel с объектами
|
||
output_excel = str(self.temp_dir / "integration_test_updated.xlsx")
|
||
success = excel_processor.update_excel_with_cadastral_records(records, output_excel)
|
||
self.assertTrue(success, "Обновление Excel должно быть успешным")
|
||
|
||
print(f" ✅ Excel обновлен: {Path(output_excel).name}")
|
||
|
||
# Проверяем созданный файл
|
||
self.assertTrue(os.path.exists(output_excel))
|
||
|
||
# Показываем первые совпадения
|
||
if matching_numbers:
|
||
print(f" 🎯 Первые 5 совпадений:")
|
||
for i, number in enumerate(sorted(matching_numbers)[:5]):
|
||
print(f" {i+1}. {number}")
|
||
|
||
def test_06_new_implementation_features(self):
|
||
"""Тестирует особенности новой реализации с объектами"""
|
||
print("\n=== ТЕСТ 6: НОВАЯ РЕАЛИЗАЦИЯ ===")
|
||
|
||
if not os.path.exists(self.test_xml_dir):
|
||
self.skipTest("Тестовая директория не найдена")
|
||
|
||
seeker = FileSeeker(self.test_xml_dir)
|
||
records = seeker.process_files()
|
||
|
||
# Проверяем, что каждая запись - это объект с множественными номерами
|
||
objects_with_multiple_numbers = [r for r in records if len(r.all_numbers) > 1]
|
||
|
||
print(f" 📋 Всего объектов: {len(records)}")
|
||
print(f" 🔗 Объектов с несколькими номерами: {len(objects_with_multiple_numbers)}")
|
||
|
||
# Показываем примеры объектов с несколькими номерами
|
||
if objects_with_multiple_numbers:
|
||
print(f" 📋 Примеры объектов с несколькими номерами:")
|
||
for i, record in enumerate(objects_with_multiple_numbers[:3]):
|
||
print(f" {i+1}. Основной: {record.main_number}")
|
||
print(f" Всего номеров: {len(record.all_numbers)}")
|
||
print(f" Другие номера: {sorted(record.other_numbers)}")
|
||
|
||
# Проверяем уникальность основных номеров
|
||
main_numbers = [r.main_number for r in records]
|
||
unique_main_numbers = set(main_numbers)
|
||
|
||
print(f" 🏷️ Уникальных основных номеров: {len(unique_main_numbers)}")
|
||
print(f" 📊 Всего номеров во всех объектах: {sum(len(r.all_numbers) for r in records)}")
|
||
|
||
@classmethod
|
||
def tearDownClass(cls):
|
||
"""Очистка после тестов"""
|
||
print("\n=== ОЧИСТКА ===")
|
||
# Можно добавить очистку временных файлов если нужно
|
||
pass
|
||
|
||
|
||
def run_all_tests():
|
||
"""Запускает все тесты с подробным выводом"""
|
||
print("🚀 ЗАПУСК ОБЪЕДИНЕННЫХ ТЕСТОВ KADASTR PARSER")
|
||
print("=" * 60)
|
||
|
||
# Создаем тестовый набор
|
||
loader = unittest.TestLoader()
|
||
suite = loader.loadTestsFromTestCase(KadastrParserTests)
|
||
|
||
# Запускаем тесты с подробным выводом
|
||
runner = unittest.TextTestRunner(verbosity=2, stream=None)
|
||
result = runner.run(suite)
|
||
|
||
print("\n" + "=" * 60)
|
||
print("🎯 ИТОГОВЫЕ РЕЗУЛЬТАТЫ:")
|
||
print(f" ✅ Успешных тестов: {result.testsRun - len(result.failures) - len(result.errors)}")
|
||
print(f" ❌ Неудачных тестов: {len(result.failures)}")
|
||
print(f" 💥 Ошибок: {len(result.errors)}")
|
||
print(f" ⏭️ Пропущенных: {len(result.skipped)}")
|
||
|
||
if result.failures:
|
||
print("\n❌ НЕУДАЧИ:")
|
||
for test, error in result.failures:
|
||
print(f" • {test}: {error}")
|
||
|
||
if result.errors:
|
||
print("\n💥 ОШИБКИ:")
|
||
for test, error in result.errors:
|
||
print(f" • {test}: {error}")
|
||
|
||
success = len(result.failures) == 0 and len(result.errors) == 0
|
||
print(f"\n🏆 ОБЩИЙ РЕЗУЛЬТАТ: {'✅ ВСЕ ТЕСТЫ ПРОШЛИ' if success else '❌ ЕСТЬ ПРОБЛЕМЫ'}")
|
||
|
||
return success
|
||
|
||
|
||
if __name__ == "__main__":
|
||
run_all_tests()
|