You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Moto3模拟指定Athena表的查询结果值?

解决Moto3中控制Athena查询结果的问题(无提前Execution ID时)

针对你遇到的无法提前获取Query Execution ID、defaultdict不生效的问题,这里提供两种直接可行的解决方案:


方案1:提前捕获Execution ID并注入预设结果

业务代码中调用start_query_execution后会直接返回包含QueryExecutionId的响应,你可以在测试流程中先触发该调用拿到ID,再将预设结果注入Moto的backend,之后再执行后续业务逻辑。

示例代码:

def test_athena_query():
    # 初始化Athena客户端与backend
    athena_client = boto3.client("athena", region_name="us-east-1")
    backend = athena_backends[DEFAULT_ACCOUNT_ID]["us-east-1"]
    
    # 1. 先执行start_query_execution获取execution_id
    exec_response = athena_client.start_query_execution(
        QueryString='SELECT * FROM xyz',
        QueryExecutionContext={'Database': 'myDb'},
        ResultConfiguration={'OutputLocation': 's3://test-bucket'},
        WorkGroup='myWG'
    )
    execution_id = exec_response['QueryExecutionId']
    
    # 2. 构造并注入预设查询结果
    rows = [
        {"Data": [{"VarCharValue": "xyz"}]},
        {"Data": [{"VarCharValue": "test_data"}]}
    ]
    column_info = [
        {
            "CatalogName": "awsdatacatalog",
            "SchemaName": "myDb",
            "TableName": "xyz",
            "Name": "column1",
            "Label": "column1",
            "Type": "string",
            "Precision": 0,
            "Scale": 0,
            "Nullable": "NOT_NULL",
            "CaseSensitive": True,
        }
    ]
    preset_results = QueryResults(rows=rows, column_info=column_info)
    backend.query_results[execution_id] = preset_results
    
    # 3. 执行业务代码或直接验证结果
    if exec_response['QueryExecution']['Status']['State'] == 'SUCCEEDED':
        query_results = athena_client.get_query_results(QueryExecutionId=execution_id)
        assert query_results['ResultSet']['Rows'] == rows

如果业务代码是封装好的函数无法拆分,可以用Monkey Patch替换start_query_execution,返回预设ID的同时提前注入结果:

def test_athena_patched_execution():
    athena_client = boto3.client("athena", region_name="us-east-1")
    backend = athena_backends[DEFAULT_ACCOUNT_ID]["us-east-1"]
    
    # 预设ID与结果
    mock_exec_id = "test-exec-12345"
    preset_rows = [{"Data": [{"VarCharValue": "patched_result"}]}]
    preset_results = QueryResults(rows=preset_rows, column_info=[{"Name": "col1", "Type": "string"}])
    backend.query_results[mock_exec_id] = preset_results
    
    # 替换原方法
    original_start = athena_client.start_query_execution
    def patched_start(**kwargs):
        return {
            'QueryExecutionId': mock_exec_id,
            'QueryExecution': {'Status': {'State': 'SUCCEEDED'}}
        }
    athena_client.start_query_execution = patched_start
    
    try:
        # 执行你的业务代码
        your_athena_business_logic()
        # 后续验证结果逻辑
    finally:
        # 恢复原方法
        athena_client.start_query_execution = original_start

方案2:直接Patch AthenaBackend的get_query_results方法

既然Moto原方法会判断exec_id是否存在于query_results中,你可以直接替换该方法,绕过判断逻辑,强制返回预设结果。

示例代码:

import types
from moto.athena.models import QueryResults

def test_athena_patch_backend_method():
    athena_client = boto3.client("athena", region_name="us-east-1")
    backend = athena_backends[DEFAULT_ACCOUNT_ID]["us-east-1"]
    
    # 构造预设结果
    preset_rows = [{"Data": [{"VarCharValue": "forced_result"}]}]
    preset_results = QueryResults(rows=preset_rows, column_info=[{"Name": "col1", "Type": "string"}])
    
    # 替换get_query_results方法
    original_get_results = backend.get_query_results
    def patched_get_results(self, exec_id):
        return preset_results
    
    backend.get_query_results = types.MethodType(patched_get_results, backend)
    
    try:
        # 执行业务代码,所有get_query_results调用都会返回预设结果
        your_athena_business_logic()
    finally:
        # 恢复原方法
        backend.get_query_results = original_get_results

补充说明

你之前用defaultdict无效的原因是:Moto的get_query_results方法中,exec_id in self.query_results的判断不会触发defaultdict的默认值生成(仅当直接访问键时才会触发),因此判断会返回False,最终返回空结果。上述两种方案均绕过了这个判断逻辑,或提前注入了合法的Execution ID与对应结果。

内容的提问来源于stack exchange,提问作者Randomize

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 10:51:11