如何通过tox mock awsglue模块?遇模块缺失等问题求解决方案
解决AWS Glue模块在单元测试中的导入问题
问题场景
业务代码(utils/fetch_arguments.py):
from awsglue.utils import getResolvedOptions from functools import * class FetchArguments: def __init__(self) -> None: pass def fetch_arguments(self, args): # 业务逻辑代码
单元测试代码:
import unittest from unittest.mock import patch from utils.fetch_arguments import FetchArguments class TestFetchArguments(unittest.TestCase): @patch("utils.fetch_arguments.awsglue.utils.getResolvedOptions") def test_fetch_arguments_with_fullload(self, mock_get_resolved_options): # 测试逻辑代码
通过tox运行测试时抛出错误:
from awsglue.dynamicframe import DynamicFrame ModuleNotFoundError: No module named 'awsglue'
已尝试的无效方案
- 安装aws-glue-libs并复制到tox的site-packages:测试可运行,但无法在CI/CD环境中自动化执行
- 直接用
python -m unittest discover -v运行:出现ModuleNotFoundError: No module named 'models' - 在setup.py中添加aws-glue-libs的Git地址:无法被包管理工具识别
可行解决方案
方案1:全局Mock整个AWS Glue模块
问题根源是测试执行时,项目中其他模块(如models)也导入了AWS Glue的子模块,仅Mock单个getResolvedOptions函数无法阻止真实的模块导入尝试。可以提前在测试中Mock整个awsglue包及其子模块:
修改测试文件如下:
import sys import unittest from unittest.mock import Mock, patch # 提前注入Mock的awsglue模块到系统模块列表 mock_awsglue = Mock() sys.modules['awsglue'] = mock_awsglue sys.modules['awsglue.utils'] = mock_awsglue.utils sys.modules['awsglue.dynamicframe'] = mock_awsglue.dynamicframe # 现在可以安全导入被测试模块 from utils.fetch_arguments import FetchArguments class TestFetchArguments(unittest.TestCase): @patch("utils.fetch_arguments.getResolvedOptions") def test_fetch_arguments_with_fullload(self, mock_get_resolved_options): # 测试逻辑示例 mock_get_resolved_options.return_value = {"full_load": "true"} fetcher = FetchArguments() result = fetcher.fetch_arguments(["--full_load", "true"]) self.assertEqual(result["full_load"], "true")
方案2:通过tox配置解决路径依赖(针对models模块找不到的问题)
如果直接运行测试时出现models模块找不到的问题,说明项目根目录未被加入Python路径。可以在tox.ini中配置PYTHONPATH:
[tox] envlist = py38, py39 skipsdist = true [testenv] deps = pytest commands = python -m unittest discover -v setenv = PYTHONPATH = {toxinidir}
方案3:使用mock库的patch.dict批量Mock模块
也可以用patch.dict一次性Mock所有需要的AWS Glue子模块,代码更简洁:
import unittest from unittest.mock import patch, Mock @patch.dict('sys.modules', { 'awsglue': Mock(), 'awsglue.utils': Mock(), 'awsglue.dynamicframe': Mock() }) class TestFetchArguments(unittest.TestCase): @patch("utils.fetch_arguments.getResolvedOptions") def test_fetch_arguments_with_fullload(self, mock_get_resolved_options): # 测试逻辑代码 pass
这些方案无需安装真实的AWS Glue库,完全通过Mock实现,适配本地测试和CI/CD环境。
内容的提问来源于stack exchange,提问作者whatsinthename
相关产品推荐
相关产品推荐

