如何对依赖API响应、文件目录等外部依赖的Python函数进行单元测试
文件下载函数单元测试编写方案
单元测试的核心原则是只测当前函数的逻辑,所有不属于当前函数的外部依赖全部用模拟对象替换,避免外部环境影响测试结果。
第一步:梳理外部依赖
你提供的download_file函数共有3个外部依赖,全部不需要真实执行,用模拟方式替换即可:
requests.get:网络请求依赖,不需要真实发送HTTP请求get_file_path:第三方工具函数,不需要真实生成路径- 内置
open方法:文件系统依赖,不需要真实写入磁盘
第二步:测试工具选择
直接用Python标准库自带的unittest.mock做模拟,测试框架用通用的pytest即可,不需要额外安装其他依赖。
第三步:基础测试代码示例
from unittest.mock import patch, MagicMock from your_module import download_file # 替换为你函数实际所在的模块名 def test_download_file_normal_flow(): # 准备测试用的模拟数据 test_url = "https://example.com/test_file" test_filename = "test.txt" test_file_content = b"this is test file content" test_generate_path = "/home/user/files/test.txt" # 模拟requests.get返回的响应对象 mock_resp = MagicMock() mock_resp.content = test_file_content # 批量替换三个外部依赖 with patch("your_module.get") as mock_get, \ patch("your_module.get_file_path") as mock_get_path, \ patch("your_module.open", create=True) as mock_open: # 给模拟的依赖设置返回值 mock_get.return_value = mock_resp mock_get_path.return_value = test_generate_path # 执行待测试的下载函数 download_file(test_url, test_filename) # 逐项验证逻辑是否符合预期 # 1. 验证是否用传入的url调用了请求方法 mock_get.assert_called_once_with(test_url) # 2. 验证是否用传入的文件名调用了路径生成方法 mock_get_path.assert_called_once_with(test_filename) # 3. 验证是否用正确的路径和写模式打开了文件 mock_open.assert_called_once_with(test_generate_path, "wb") # 4. 验证是否把请求拿到的内容正确写入了文件 mock_open.return_value.__enter__.return_value.write.assert_called_once_with(test_file_content)
注意事项
- patch的路径要写下载函数所在模块里导入的依赖路径:比如你的下载函数写在
utils/download.py里,该文件里是from requests import get,那你要patch的路径是utils.download.get,不是直接patchrequests.get,这是新手最常见的错误。
第四步:可选的异常场景测试
如果需要更高的测试覆盖率,可以补充异常场景的测试,比如网络超时、文件写入失败的情况,示例如下:
from requests.exceptions import Timeout def test_download_file_network_error(): test_url = "https://example.com/test_file" test_filename = "test.txt" with patch("your_module.get") as mock_get: # 模拟请求抛出超时异常 mock_get.side_effect = Timeout("连接超时") # 验证调用函数时会正确抛出异常 try: download_file(test_url, test_filename) # 走到这里说明没有抛出异常,测试不通过 assert False, "网络异常时应该抛出Timeout错误" except Timeout: # 正常抛出异常,测试通过 assert True
内容的提问来源于stack exchange,提问作者ToastedGuy2
相关产品推荐
相关产品推荐

