""" 字典取值工具单元测试(dict_utils) ============================================================= 验证 dict_utils 按 code 取字典项 / value→name 映射(消费端取值): - int / str 值都能命中(value 统一 str 归一) - 未知 code / 未知 value → None - 内存缓存命中(第二次取值不再查库) - clear_cache 失效后重新加载 """ import pytest from src.core.database import db from src.modules.dictionary import dict_utils from src.modules.dictionary.dict.repository import DictRepository from src.modules.dictionary.dict_item.repository import DictItemRepository @pytest.fixture(autouse=True) def _clear_dict_cache(): """每用例前后清空 dict_utils 缓存,避免用例间 sqlite 库重建导致的脏缓存""" dict_utils.clear_cache() yield dict_utils.clear_cache() def _seed_gender(): """构造 gender 字典(男/"1"、女/"2"、保密/"3"),幂等""" if DictRepository.first_by({"code": "gender"}): return dict_obj = DictRepository.create(name="性别", code="gender", sort=1, create_user="system") for name, value, sort in [("男", "1", 1), ("女", "2", 2), ("保密", "3", 3)]: DictItemRepository.create( dict_id=dict_obj.id, name=name, value=value, sort=sort, create_user="system", ) db.session.commit() class TestGetName: """int / str 值命中与未知值兜底""" def test_int_value_hits(self, app): with app.app_context(): _seed_gender() assert dict_utils.get_name("gender", 1) == "男" assert dict_utils.get_name("gender", 2) == "女" assert dict_utils.get_name("gender", 3) == "保密" def test_str_value_hits(self, app): with app.app_context(): _seed_gender() assert dict_utils.get_name("gender", "1") == "男" assert dict_utils.get_name("gender", "2") == "女" def test_unknown_value_returns_none(self, app): with app.app_context(): _seed_gender() assert dict_utils.get_name("gender", 99) is None def test_unknown_code_returns_none(self, app): with app.app_context(): assert dict_utils.get_name("not_exist", 1) is None class TestGetValueMap: """映射键统一为 str""" def test_map_keys_are_str(self, app): with app.app_context(): _seed_gender() value_map = dict_utils.get_value_map("gender") assert value_map == {"1": "男", "2": "女", "3": "保密"} class TestCache: """内存缓存命中 + clear_cache 失效""" def test_cache_hit_queries_db_once(self, app, monkeypatch): with app.app_context(): _seed_gender() original = DictItemRepository.list_by_code calls = {"n": 0} def spy(cls, code, **kwargs): calls["n"] += 1 return original(code, **kwargs) monkeypatch.setattr(DictItemRepository, "list_by_code", classmethod(spy)) assert dict_utils.get_name("gender", 1) == "男" assert dict_utils.get_name("gender", 2) == "女" assert dict_utils.get_name("gender", 3) == "保密" assert calls["n"] == 1 def test_clear_cache_reloads(self, app): with app.app_context(): _seed_gender() assert dict_utils.get_name("gender", 1) == "男" dict_utils.clear_cache("gender") # 失效后重新读取仍正确 assert dict_utils.get_name("gender", 2) == "女" class TestGetDictItems: """字典项列表返回 {value, name, sort}""" def test_items_shape_and_order(self, app): with app.app_context(): _seed_gender() items = dict_utils.get_dict_items("gender") assert [it["value"] for it in items] == ["1", "2", "3"] assert items[0] == {"value": "1", "name": "男", "sort": 1}