2013-04-21

requests でテストした、その後ですよ

Web API をもつアプリケーションのテストを、Python と requests ライブラリを使って書いています。それはよいのですが、テストが通らなかったときですよ。酔ってますよ、もう、休日に仕事してぜんぜんはかどらなくて。それと、これとは別ですけど。

アプリケーションが Python で書かれていない場合、開発者が Python 環境を自由に使えない場合があります。テストのレポートを再現するためだけに、Python モジュールをインストールしてもらうのも気が引けます。

というわけで、requests を使ったアクセスを、 curl で再現するように hooks に追加することにしました。最初から curl 使えよとか、いろいろあると思いますが、すでにレイヤをまたいで requests 使ってたもので。

import curledrequests as requests
requests.debug = True
requests.post('http://example.com/', auth=("foo", "bar"), data={"hoge":"moge"})

のように書くと、

$ curl http://example.com/ -u 'foo:bar' -w '\n%{http_code}\n'
... ここに body が入る ...
200

と表示されます。これを Web API 開発者に渡して、再現してもらうことができます。gist においてあります。

"""requests wrapper
>>> import curledrequests as requests
you can use this as requests module, but...
>>> requests.debug = True
>>> requests.get('http://example.com/')
curl http://example.com/
Hello
200
"""
from urllib import unquote
from base64 import b64decode
from requests import *
debug = False
def wrap(func, *args, **kw):
def wrapper(*args, **kw):
if debug:
kw['hooks'] = {'response': print_curl}
return func(*args, **kw)
return wrapper
def print_curl(res):
params = [res.url]
# method
method = res.request.method
if method != 'GET':
params = ['-X', method] + params
# data
body = res.request.body
if body:
params += ['--data', "'%s'" % unquote(body)]
# auth
auth = res.request.headers.get('Authorization')
if auth:
_, credential = auth.split(' ')
params += ['-u', "'%s'" % b64decode(credential)]
# status code
params += ['-w', r"'\n%{http_code}\n'"]
# render
print '$ curl ' + ' '.join(params)
print res.content
print res.status_code
print
get = wrap(get)
post = wrap(post)
delete = wrap(delete)
put = wrap(put)