""" 共享测试 fixtures 直接加载生产代码 standard_service.py(绕过 package __init__.py 的重依赖链) """ import sys import os import types import importlib.util import pytest current_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(os.path.dirname(current_dir)) if project_root not in sys.path: def _load_production_module(): """ 直接从文件加载生产代码 standard_service.py 绕过 core.construction_review.component.__init__.py 的重依赖链 """ # Mock 生产代码依赖的 logger 和 config if 'foundation.observability.logger.loggering' not in sys.modules: mock_logger_mod = types.ModuleType('foundation.observability.logger.loggering') _null_logger = type('_NullLogger', (), { 'info': lambda self, *a, **kw: None, 'warning': lambda self, *a, **kw: None, 'error': lambda self, *a, **kw: None, 'debug': lambda self, *a, **kw: None, })() mock_logger_mod.review_logger = _null_logger sys.modules['foundation.observability.logger.loggering'] = mock_logger_mod if 'foundation.infrastructure.config.config' not in sys.modules: mock_config_mod = types.ModuleType('foundation.infrastructure.config.config') mock_config_mod.config_handler = type('_ConfigHandler', (), { 'get': staticmethod(lambda section, key, default=None: default) })() sys.modules['foundation.infrastructure.config.config'] = mock_config_mod # 从文件直接加载 standard_service.py module_path = os.path.join( project_root, 'core', 'construction_review', 'component', 'standard_matching', 'standard_service.py' ) spec = importlib.util.spec_from_file_location('production_standard_service', module_path) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod # 加载生产模块 _prod = _load_production_module() # 导出生产代码的类 StandardRepository = _prod.StandardRepository StandardMatcher = _prod.StandardMatcher StandardMatchResult = _prod.StandardMatchResult StandardRecord = _prod.StandardRecord MatchResultCode = _prod.MatchResultCode ValidityStatus = _prod.ValidityStatus # ======================================== # 默认测试数据集(覆盖5种匹配状态) # ======================================== DEFAULT_MOCK_DATA = [ # 情况1: 正常现行标准 {"id": 1, "standard_name": "铁路桥涵设计规范", "standard_number": "TB 10002-2017", "validity": "XH"}, {"id": 2, "standard_name": "铁路工程抗震设计规范", "standard_number": "GB 50111-2006", "validity": "XH"}, {"id": 3, "standard_name": "铁路混凝土工程施工质量验收标准", "standard_number": "TB 10424-2018", "validity": "XH"}, # 情况4: 不匹配(年份错误)- 输入2023,实际2024 {"id": 4, "standard_name": "公路水运危险性较大工程专项施工方案编制审查规程", "standard_number": "JT/T 1495-2024", "validity": "XH"}, # 情况2: 被替代(废止+有现行替代) {"id": 5, "standard_name": "起重机 钢丝绳 保养、维护、检验和报废", "standard_number": "GB/T 5972-2016", "validity": "FZ"}, {"id": 6, "standard_name": "起重机 钢丝绳 保养、维护、检验和报废", "standard_number": "GB/T 5972-2023", "validity": "XH"}, # 情况3: 废止无替代 {"id": 7, "standard_name": "缆索起重机", "standard_number": "GB/T 28756-2012", "validity": "FZ"}, {"id": 8, "standard_name": "电力高处作业防坠器", "standard_number": "DL/T 1147-2009", "validity": "FZ"}, ] def create_matcher(mock_data=None): """工厂函数:创建加载了测试数据的 matcher""" repo = StandardRepository() repo.load_data(mock_data or DEFAULT_MOCK_DATA) return StandardMatcher(repo) def check_standards_via_matcher(matcher, standards): """模拟 StandardMatchingService.check_standards 的批量检查逻辑""" results = [] for idx, std in enumerate(standards, start=1): result = matcher.match( seq_no=idx, input_name=std.get("standard_name", ""), input_number=std.get("standard_number", "") ) if result is not None: results.append(result) return results @pytest.fixture def repository(): """创建并加载默认测试数据的仓库""" repo = StandardRepository() repo.load_data(DEFAULT_MOCK_DATA) return repo @pytest.fixture def matcher(repository): """创建匹配器实例(基于默认数据)""" return StandardMatcher(repository)