Python调用GitHub API获取分支单元测试报错问题排查
问题
我编写了Python代码来获取指定GitHub仓库的所有分支,参考了GitHub API的分支列表接口,但运行单元测试时始终出现AttributeError: 'NoneType' object has no attribute 'json'错误,response一直是None。不确定问题出在API调用代码还是测试代码中,相关代码如下:
业务代码
@staticmethod def get_branches(git_base, org, repo): github_repo_url = f"https://{git_base}/api/v3/repos/{org}/{repo}" collected_all_branches: bool = False page = 1 github_branches = [] # collect all branches in repo while not collected_all_branches: response = (requests.get(f"{github_repo_url}/branches/?per_page=100&page={page}", headers=HEADERS)) if len(response.json()) == 0: collected_all_branches = True else: github_branches.extend([response["name"] for response in response.json()]) page = page + 1 return github_branches
单元测试代码
@patch.object(requests, "get", return_value=None) def test_get_branches(self, mock_get): r = GithubService.get_branches("test", "test", "test") mock_get.assert_called_with("test", "test", "test")
问题原因与修复方案
1. 测试代码的核心问题
- 你给
mock_get设置了return_value=None,导致业务代码中requests.get返回None,调用response.json()自然会触发NoneType属性错误。 assert_called_with的参数完全错误:业务代码中requests.get接收的是拼接后的完整URL和headers=HEADERS参数,不是传入的三个"test"字符串。
2. 修正后的单元测试代码
需要用MagicMock模拟一个包含json()方法的响应对象,同时验证调用参数的正确性:
from unittest.mock import patch, MagicMock @patch.object(requests, "get") def test_get_branches(self, mock_get): # 模拟第一页的分支数据 mock_response = MagicMock() mock_response.json.return_value = [{"name": "main"}, {"name": "dev"}] # 模拟第二页返回空列表,触发循环结束 mock_response_empty = MagicMock() mock_response_empty.json.return_value = [] # 设置mock_get的返回值序列:第一次返回有数据的响应,第二次返回空响应 mock_get.side_effect = [mock_response, mock_response_empty] r = GithubService.get_branches("test", "test", "test") # 验证调用次数和参数 expected_url_page1 = "https://test/api/v3/repos/test/test/branches/?per_page=100&page=1" expected_url_page2 = "https://test/api/v3/repos/test/test/branches/?per_page=100&page=2" mock_get.assert_any_call(expected_url_page1, headers=HEADERS) mock_get.assert_any_call(expected_url_page2, headers=HEADERS) # 验证返回结果是否正确 self.assertEqual(r, ["main", "dev"])
3. 业务代码的潜在问题修复
- 变量名冲突:列表推导式里用
response作为迭代变量,覆盖了外层的请求响应对象,容易引发混淆,建议修改为branch:github_branches.extend([branch["name"] for branch in response.json()]) - 异常处理缺失:没有处理请求失败的情况(比如网络错误、API返回4xx/5xx状态码),建议添加状态码校验和异常捕获:
response = requests.get(...) response.raise_for_status() # 触发HTTPError如果状态码不是200
内容的提问来源于stack exchange,提问作者user19251203
相关产品推荐
相关产品推荐

