如何在Python中使用Google HttpMock?
我刚接触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 个回答
对于其他寻找答案的人,这里有个解决办法,来自我在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')
),不加其他参数,这样就能正常工作。
books-discovery.json 这个文件是用来构建图书 API 的发现服务文件,同时也是一个保存的响应。
可以参考文档中的说明:
在你开发和测试应用程序时,保存实际的 API 响应到像 books-discovery.json 或 books-android.json 这样的文件中,是个不错的主意,这样可以在测试时使用。
这里是 books-discovery.json 文件:
还有 books-android.json 文件:
有了这两个文件,示例就可以运行了。
所以你所做的就是告诉系统:“与其发起这个 HTTP 请求,不如直接返回这些内容和状态。”
不过,你仍然需要提供合适的内容,这样代码才能正常工作。你只是不用依赖 HTTP 请求来获取这些内容。