conftest.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. """
  2. 共享测试 fixtures
  3. 直接加载生产代码 standard_service.py(绕过 package __init__.py 的重依赖链)
  4. """
  5. import sys
  6. import os
  7. import types
  8. import importlib.util
  9. import pytest
  10. current_dir = os.path.dirname(os.path.abspath(__file__))
  11. project_root = os.path.dirname(os.path.dirname(current_dir))
  12. if project_root not in sys.path:
  13. def _load_production_module():
  14. """
  15. 直接从文件加载生产代码 standard_service.py
  16. 绕过 core.construction_review.component.__init__.py 的重依赖链
  17. """
  18. # Mock 生产代码依赖的 logger 和 config
  19. if 'foundation.observability.logger.loggering' not in sys.modules:
  20. mock_logger_mod = types.ModuleType('foundation.observability.logger.loggering')
  21. _null_logger = type('_NullLogger', (), {
  22. 'info': lambda self, *a, **kw: None,
  23. 'warning': lambda self, *a, **kw: None,
  24. 'error': lambda self, *a, **kw: None,
  25. 'debug': lambda self, *a, **kw: None,
  26. })()
  27. mock_logger_mod.review_logger = _null_logger
  28. sys.modules['foundation.observability.logger.loggering'] = mock_logger_mod
  29. if 'foundation.infrastructure.config.config' not in sys.modules:
  30. mock_config_mod = types.ModuleType('foundation.infrastructure.config.config')
  31. mock_config_mod.config_handler = type('_ConfigHandler', (), {
  32. 'get': staticmethod(lambda section, key, default=None: default)
  33. })()
  34. sys.modules['foundation.infrastructure.config.config'] = mock_config_mod
  35. # 从文件直接加载 standard_service.py
  36. module_path = os.path.join(
  37. project_root,
  38. 'core', 'construction_review', 'component', 'standard_matching', 'standard_service.py'
  39. )
  40. spec = importlib.util.spec_from_file_location('production_standard_service', module_path)
  41. mod = importlib.util.module_from_spec(spec)
  42. spec.loader.exec_module(mod)
  43. return mod
  44. # 加载生产模块
  45. _prod = _load_production_module()
  46. # 导出生产代码的类
  47. StandardRepository = _prod.StandardRepository
  48. StandardMatcher = _prod.StandardMatcher
  49. StandardMatchResult = _prod.StandardMatchResult
  50. StandardRecord = _prod.StandardRecord
  51. MatchResultCode = _prod.MatchResultCode
  52. ValidityStatus = _prod.ValidityStatus
  53. # ========================================
  54. # 默认测试数据集(覆盖5种匹配状态)
  55. # ========================================
  56. DEFAULT_MOCK_DATA = [
  57. # 情况1: 正常现行标准
  58. {"id": 1, "standard_name": "铁路桥涵设计规范", "standard_number": "TB 10002-2017", "validity": "XH"},
  59. {"id": 2, "standard_name": "铁路工程抗震设计规范", "standard_number": "GB 50111-2006", "validity": "XH"},
  60. {"id": 3, "standard_name": "铁路混凝土工程施工质量验收标准", "standard_number": "TB 10424-2018", "validity": "XH"},
  61. # 情况4: 不匹配(年份错误)- 输入2023,实际2024
  62. {"id": 4, "standard_name": "公路水运危险性较大工程专项施工方案编制审查规程", "standard_number": "JT/T 1495-2024", "validity": "XH"},
  63. # 情况2: 被替代(废止+有现行替代)
  64. {"id": 5, "standard_name": "起重机 钢丝绳 保养、维护、检验和报废", "standard_number": "GB/T 5972-2016", "validity": "FZ"},
  65. {"id": 6, "standard_name": "起重机 钢丝绳 保养、维护、检验和报废", "standard_number": "GB/T 5972-2023", "validity": "XH"},
  66. # 情况3: 废止无替代
  67. {"id": 7, "standard_name": "缆索起重机", "standard_number": "GB/T 28756-2012", "validity": "FZ"},
  68. {"id": 8, "standard_name": "电力高处作业防坠器", "standard_number": "DL/T 1147-2009", "validity": "FZ"},
  69. ]
  70. def create_matcher(mock_data=None):
  71. """工厂函数:创建加载了测试数据的 matcher"""
  72. repo = StandardRepository()
  73. repo.load_data(mock_data or DEFAULT_MOCK_DATA)
  74. return StandardMatcher(repo)
  75. def check_standards_via_matcher(matcher, standards):
  76. """模拟 StandardMatchingService.check_standards 的批量检查逻辑"""
  77. results = []
  78. for idx, std in enumerate(standards, start=1):
  79. result = matcher.match(
  80. seq_no=idx,
  81. input_name=std.get("standard_name", ""),
  82. input_number=std.get("standard_number", "")
  83. )
  84. if result is not None:
  85. results.append(result)
  86. return results
  87. @pytest.fixture
  88. def repository():
  89. """创建并加载默认测试数据的仓库"""
  90. repo = StandardRepository()
  91. repo.load_data(DEFAULT_MOCK_DATA)
  92. return repo
  93. @pytest.fixture
  94. def matcher(repository):
  95. """创建匹配器实例(基于默认数据)"""
  96. return StandardMatcher(repository)