如何在Python中使用Google HttpMock?

4 投票
2 回答
1979 浏览
提问于 2025-04-18 07:02

我刚接触Google的API,现在想为我做的一些功能写单元测试。Google的HttpMock看起来非常适合我想做的事情,但无论我怎么尝试,示例代码都无法运行。以下是我从Google复制的完整示例代码:

from apiclient.discovery import build
from apiclient.http import HttpMock
import pprint

http = HttpMock('books-discovery.json', {'status': '200'})
api_key = 'your_api_key'
service = build('books', 'v1', http=http, developerKey=api_key)
request = service.volumes().list(source='public', q='android')
http = HttpMock('books-android.json', {'status': '200'})
response = request.execute(http=http)
pprint.pprint(response)

我试着把books-discovery.json设置成有效的json格式,但还是出现了这个错误:

Traceback (most recent call last):
  File "testthing.py", line 7, in <module>
    service = build('books', 'v1', http=http, developerKey=api_key)
  File "/Users/Eli/.virtualenvs/BigQueryTest/lib/python2.7/site-packages/oauth2client/util.py", line 132, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/Users/Eli/.virtualenvs/BigQueryTest/lib/python2.7/site-packages/apiclient/discovery.py", line 207, in build
    developerKey=developerKey, model=model, requestBuilder=requestBuilder)
  File "/Users/Eli/.virtualenvs/BigQueryTest/lib/python2.7/site-packages/oauth2client/util.py", line 132, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/Users/Eli/.virtualenvs/BigQueryTest/lib/python2.7/site-packages/apiclient/discovery.py", line 249, in build_from_document
    base = urlparse.urljoin(service['rootUrl'], service['servicePath'])
KeyError: 'rootUrl'

我到底哪里做错了?books-discovery.json是不是需要某种特别的格式,但在任何地方都没有提到?

2 个回答

0

对于其他寻找答案的人,这里有个解决办法,来自我在GitHub问题上的评论

问题似乎是因为 build() 会使用你提供的 http 对象来获取发现文档,即使你在使用 HttpMock。如果缓存被禁用,或者你没有文档的缓存版本(在我的情况下,它在 Travis CI 上有,但在我的本地机器上没有),这会导致失败——这是一种不确定的失败,取决于你的缓存状态,真是太棒了。

要重现这个问题:

#!/usr/bin/env python

from apiclient.discovery import build
from apiclient.http import HttpMockSequence

http = HttpMockSequence([({'status': '200'}, "{}")])
build('calendar', 'v3', cache_discovery=False, http=http)

错误追踪信息:

Traceback (most recent call last):
  File "reproduce-bug.py", line 7, in <module>
    build('calendar', 'v3', cache_discovery=False, http=http)
  File "/Library/Python/2.7/site-packages/oauth2client/util.py", line 137, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/googleapiclient/discovery.py",line
    credentials=credentials)
  File "/Library/Python/2.7/site-packages/oauth2client/util.py", line 137, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/googleapiclient/discovery.py", line 318, in build_from_document
    base = urljoin(service['rootUrl'], service['servicePath'])
KeyError: 'rootUrl'

在我抓狂之后,我发现了一个解决方法:只需在使用模拟之前调用 build('calendar', 'v3')(或者在你的情况下,build('books', 'v1')),不加其他参数,这样就能正常工作。

1

books-discovery.json 这个文件是用来构建图书 API 的发现服务文件,同时也是一个保存的响应。

可以参考文档中的说明:

在你开发和测试应用程序时,保存实际的 API 响应到像 books-discovery.json 或 books-android.json 这样的文件中,是个不错的主意,这样可以在测试时使用。

这里是 books-discovery.json 文件:

https://gist.github.com/Bachmann1234/19fddfb983022218204a

还有 books-android.json 文件:

https://gist.github.com/Bachmann1234/a2b4207caa29dbc23e29

有了这两个文件,示例就可以运行了。

所以你所做的就是告诉系统:“与其发起这个 HTTP 请求,不如直接返回这些内容和状态。”

不过,你仍然需要提供合适的内容,这样代码才能正常工作。你只是不用依赖 HTTP 请求来获取这些内容。

撰写回答