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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 10:36:26