"""dict_util 字典读取工具:列表/映射/单值读取,进程内缓存与失效行为。""" from types import SimpleNamespace from utils import dict_util from utils.dict_util import ( get_dict_items, get_dict_label, get_dict_map, invalidate_dict, invalidate_dicts_by_ids, ) def _clear_cache(): dict_util._dict_cache.clear() def _rows(): # 刻意乱序:女(sort=5)、男(sort=1)、保密(sort=10),校验按 sort+id 升序输出 return [ SimpleNamespace(id=2, name='女', value='2', sort=5), SimpleNamespace(id=1, name='男', value='1', sort=1), SimpleNamespace(id=3, name='保密', value='3', sort=10), ] class _FakeQuery: def __init__(self, rows): self._rows = rows def all(self): return self._rows def _patch_repo(monkeypatch, dict_obj): monkeypatch.setattr(dict_util.dict_repo, 'get_one', lambda **kw: dict_obj) monkeypatch.setattr(dict_util.dictitem_repo, 'filter_by', lambda **kw: _FakeQuery(_rows())) # ============ 读取 ============ def test_get_dict_map_maps_value_to_label(monkeypatch): _clear_cache() _patch_repo(monkeypatch, SimpleNamespace(id=1, code='gender', name='性别')) assert get_dict_map('gender') == {'1': '男', '2': '女', '3': '保密'} def test_get_dict_items_sorted_by_sort_then_id(monkeypatch): _clear_cache() _patch_repo(monkeypatch, SimpleNamespace(id=1, code='gender', name='性别')) assert [it['value'] for it in get_dict_items('gender')] == ['1', '2', '3'] def test_get_dict_label_normalizes_value_to_str(monkeypatch): _clear_cache() _patch_repo(monkeypatch, SimpleNamespace(id=1, code='gender', name='性别')) # 用户存整数 1,字典项 value 是字符串 '1',需自动转字符串匹配 assert get_dict_label('gender', 1) == '男' assert get_dict_label('gender', '2') == '女' assert get_dict_label('gender', 99) is None assert get_dict_label('gender', 99, '未知') == '未知' def test_get_dict_map_unknown_code_returns_empty(monkeypatch): _clear_cache() _patch_repo(monkeypatch, None) assert get_dict_items('nope') == [] assert get_dict_map('nope') == {} # ============ 缓存 ============ def test_cache_hit_skips_db(monkeypatch): _clear_cache() _patch_repo(monkeypatch, SimpleNamespace(id=1, code='gender', name='性别')) get_dict_map('gender') calls = [] monkeypatch.setattr(dict_util.dict_repo, 'get_one', lambda **kw: calls.append(1) or None) get_dict_map('gender') # 命中缓存,不再访问 DB assert calls == [] def test_invalidate_dict_clears_cache(monkeypatch): _clear_cache() _patch_repo(monkeypatch, SimpleNamespace(id=1, code='gender', name='性别')) get_dict_map('gender') invalidate_dict('gender') assert dict_util._dict_cache == {} def test_invalidate_dicts_by_ids_clears_cached_codes(monkeypatch): _clear_cache() _patch_repo(monkeypatch, SimpleNamespace(id=1, code='gender', name='性别')) get_dict_map('gender') # 先填充缓存 class _FakeRows: def all(self): return [SimpleNamespace(code='gender')] monkeypatch.setattr(dict_util.dict_repo, 'filter', lambda *criteria: _FakeRows()) invalidate_dicts_by_ids({1}) assert dict_util._dict_cache == {}