单元测试时SQLite报json_contains_path不存在错误,但Postman调用正常
原因分析
核心问题是生产/运行环境与单元测试环境的数据库对JSON函数的支持不匹配:
- Postman调用时,Web应用连接的是支持
json_contains_path函数的数据库(比如PostgreSQL、MySQL 8.0+,或者版本≥3.38.0的SQLite)。 - 单元测试用的是SQLite 3.32.3,而
json_contains_path是SQLite 3.38.0才正式加入的函数,低版本SQLite完全不支持这个语法,所以执行查询时会抛出“no such function”错误。
解决方法
可以从以下几个方向处理:
1. 升级SQLite版本
把单元测试环境的SQLite版本升级到3.38.0或更高,让测试环境支持json_contains_path函数,保持查询逻辑一致。
2. 为SQLite自定义json_contains_path函数
利用SQLite的扩展机制,在单元测试初始化时注册自定义函数模拟json_contains_path的行为,示例代码:
import json import sqlite3 def json_contains_path(json_str, mode, *paths): try: data = json.loads(json_str.lower()) for path in paths: # 解析JSON路径,比如"$.applications.tech" parts = path.strip('$').split('.') current = data valid = True for part in parts: if part not in current: valid = False break current = current[part] if valid: # 匹配到任意路径就返回1(对应mode='one') return 1 return 0 except Exception: return 0 # 在单元测试的数据库初始化环节注册该函数 def setup_test_database(): conn = sqlite3.connect(':memory:') conn.create_function('json_contains_path', -1, json_contains_path) # 后续用这个连接初始化SQLAlchemy会话
3. 调整查询逻辑,兼容多数据库
修改查询代码,根据当前使用的数据库类型切换查询方式,利用SQLAlchemy的方言判断:
from sqlalchemy import inspect, or_ def search(): key = request.args.get("search") query = db.session.query(Company) base_filters = [ Company.name.like('%' + key + '%'), Company.department.like('%' + key + '%') ] # 获取当前数据库方言 dialect_name = inspect(db.engine).dialect.name json_filter = None apps = get_applications_from_key(key.lower()) if dialect_name == 'sqlite' and sqlite3.sqlite_version_info < (3, 38, 0): # 低版本SQLite用json_extract判断路径是否存在 app_filters = [] for app in apps: app_filters.append(func.json_extract(Company.app_config, f'$.applications.{app.lower()}').isnot(None)) json_filter = or_(*app_filters) else: # 支持json_contains_path的数据库用原有逻辑 json_filter = func.json_contains_path( func.lower(Company.app_config), 'one', *map(lambda app: f'$.applications.{app.lower()}', apps) ) query = query.filter(or_(*base_filters, json_filter)) return query.all()
4. 单元测试使用与生产一致的数据库
如果条件允许,单元测试直接用生产环境同款数据库(比如PostgreSQL),从根源避免数据库差异导致的兼容性问题。
内容的提问来源于stack exchange,提问作者Gerry Volta
相关产品推荐
相关产品推荐

