README.rst 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. ===============================
  2. aioresponses
  3. ===============================
  4. .. image:: https://travis-ci.org/pnuckowski/aioresponses.svg?branch=master
  5. :target: https://travis-ci.org/pnuckowski/aioresponses
  6. .. image:: https://coveralls.io/repos/github/pnuckowski/aioresponses/badge.svg?branch=master
  7. :target: https://coveralls.io/github/pnuckowski/aioresponses?branch=master
  8. .. image:: https://landscape.io/github/pnuckowski/aioresponses/master/landscape.svg?style=flat
  9. :target: https://landscape.io/github/pnuckowski/aioresponses/master
  10. :alt: Code Health
  11. .. image:: https://pyup.io/repos/github/pnuckowski/aioresponses/shield.svg
  12. :target: https://pyup.io/repos/github/pnuckowski/aioresponses/
  13. :alt: Updates
  14. .. image:: https://img.shields.io/pypi/v/aioresponses.svg
  15. :target: https://pypi.python.org/pypi/aioresponses
  16. .. image:: https://readthedocs.org/projects/aioresponses/badge/?version=latest
  17. :target: https://aioresponses.readthedocs.io/en/latest/?badge=latest
  18. :alt: Documentation Status
  19. Aioresponses is a helper to mock/fake web requests in python aiohttp package.
  20. For *requests* module there are a lot of packages that help us with testing (eg. *httpretty*, *responses*, *requests-mock*).
  21. When it comes to testing asynchronous HTTP requests it is a bit harder (at least at the beginning).
  22. The purpose of this package is to provide an easy way to test asynchronous HTTP requests.
  23. Installing
  24. ----------
  25. .. code:: bash
  26. $ pip install aioresponses
  27. Supported versions
  28. ------------------
  29. - Python 3.7+
  30. - aiohttp>=3.3.0,<4.0.0
  31. Usage
  32. --------
  33. To mock out HTTP request use *aioresponses* as a method decorator or as a context manager.
  34. Response *status* code, *body*, *payload* (for json response) and *headers* can be mocked.
  35. Supported HTTP methods: **GET**, **POST**, **PUT**, **PATCH**, **DELETE** and **OPTIONS**.
  36. .. code:: python
  37. import aiohttp
  38. import asyncio
  39. from aioresponses import aioresponses
  40. @aioresponses()
  41. def test_request(mocked):
  42. loop = asyncio.get_event_loop()
  43. mocked.get('http://example.com', status=200, body='test')
  44. session = aiohttp.ClientSession()
  45. resp = loop.run_until_complete(session.get('http://example.com'))
  46. assert resp.status == 200
  47. mocked.assert_called_once_with('http://example.com')
  48. for convenience use *payload* argument to mock out json response. Example below.
  49. **as a context manager**
  50. .. code:: python
  51. import asyncio
  52. import aiohttp
  53. from aioresponses import aioresponses
  54. def test_ctx():
  55. loop = asyncio.get_event_loop()
  56. session = aiohttp.ClientSession()
  57. with aioresponses() as m:
  58. m.get('http://test.example.com', payload=dict(foo='bar'))
  59. resp = loop.run_until_complete(session.get('http://test.example.com'))
  60. data = loop.run_until_complete(resp.json())
  61. assert dict(foo='bar') == data
  62. m.assert_called_once_with('http://test.example.com')
  63. **aioresponses allows to mock out any HTTP headers**
  64. .. code:: python
  65. import asyncio
  66. import aiohttp
  67. from aioresponses import aioresponses
  68. @aioresponses()
  69. def test_http_headers(m):
  70. loop = asyncio.get_event_loop()
  71. session = aiohttp.ClientSession()
  72. m.post(
  73. 'http://example.com',
  74. payload=dict(),
  75. headers=dict(connection='keep-alive'),
  76. )
  77. resp = loop.run_until_complete(session.post('http://example.com'))
  78. # note that we pass 'connection' but get 'Connection' (capitalized)
  79. # under the neath `multidict` is used to work with HTTP headers
  80. assert resp.headers['Connection'] == 'keep-alive'
  81. m.assert_called_once_with('http://example.com', method='POST')
  82. **allows to register different responses for the same url**
  83. .. code:: python
  84. import asyncio
  85. import aiohttp
  86. from aioresponses import aioresponses
  87. @aioresponses()
  88. def test_multiple_responses(m):
  89. loop = asyncio.get_event_loop()
  90. session = aiohttp.ClientSession()
  91. m.get('http://example.com', status=500)
  92. m.get('http://example.com', status=200)
  93. resp1 = loop.run_until_complete(session.get('http://example.com'))
  94. resp2 = loop.run_until_complete(session.get('http://example.com'))
  95. assert resp1.status == 500
  96. assert resp2.status == 200
  97. **Repeat response for the same url**
  98. E.g. for cases you want to test retrying mechanisms
  99. .. code:: python
  100. import asyncio
  101. import aiohttp
  102. from aioresponses import aioresponses
  103. @aioresponses()
  104. def test_multiple_responses(m):
  105. loop = asyncio.get_event_loop()
  106. session = aiohttp.ClientSession()
  107. m.get('http://example.com', status=500, repeat=True)
  108. m.get('http://example.com', status=200) # will not take effect
  109. resp1 = loop.run_until_complete(session.get('http://example.com'))
  110. resp2 = loop.run_until_complete(session.get('http://example.com'))
  111. assert resp1.status == 500
  112. assert resp2.status == 500
  113. **match URLs with regular expressions**
  114. .. code:: python
  115. import asyncio
  116. import aiohttp
  117. import re
  118. from aioresponses import aioresponses
  119. @aioresponses()
  120. def test_regexp_example(m):
  121. loop = asyncio.get_event_loop()
  122. session = aiohttp.ClientSession()
  123. pattern = re.compile(r'^http://example\.com/api\?foo=.*$')
  124. m.get(pattern, status=200)
  125. resp = loop.run_until_complete(session.get('http://example.com/api?foo=bar'))
  126. assert resp.status == 200
  127. **allows to make redirects responses**
  128. .. code:: python
  129. import asyncio
  130. import aiohttp
  131. from aioresponses import aioresponses
  132. @aioresponses()
  133. def test_redirect_example(m):
  134. loop = asyncio.get_event_loop()
  135. session = aiohttp.ClientSession()
  136. # absolute urls are supported
  137. m.get(
  138. 'http://example.com/',
  139. headers={'Location': 'http://another.com/'},
  140. status=307
  141. )
  142. resp = loop.run_until_complete(
  143. session.get('http://example.com/', allow_redirects=True)
  144. )
  145. assert resp.url == 'http://another.com/'
  146. # and also relative
  147. m.get(
  148. 'http://example.com/',
  149. headers={'Location': '/test'},
  150. status=307
  151. )
  152. resp = loop.run_until_complete(
  153. session.get('http://example.com/', allow_redirects=True)
  154. )
  155. assert resp.url == 'http://example.com/test'
  156. **allows to passthrough to a specified list of servers**
  157. .. code:: python
  158. import asyncio
  159. import aiohttp
  160. from aioresponses import aioresponses
  161. @aioresponses(passthrough=['http://backend'])
  162. def test_passthrough(m, test_client):
  163. session = aiohttp.ClientSession()
  164. # this will actually perform a request
  165. resp = loop.run_until_complete(session.get('http://backend/api'))
  166. **also you can passthrough all requests except specified by mocking object**
  167. .. code:: python
  168. import asyncio
  169. import aiohttp
  170. from aioresponses import aioresponses
  171. @aioresponses(passthrough_unmatched=True)
  172. def test_passthrough_unmatched(m, test_client):
  173. url = 'https://httpbin.org/get'
  174. m.get(url, status=200)
  175. session = aiohttp.ClientSession()
  176. # this will actually perform a request
  177. resp = loop.run_until_complete(session.get('http://backend/api'))
  178. # this will not perform a request and resp2.status will return 200
  179. resp2 = loop.run_until_complete(session.get(url))
  180. **aioresponses allows to throw an exception**
  181. .. code:: python
  182. import asyncio
  183. from aiohttp import ClientSession
  184. from aiohttp.http_exceptions import HttpProcessingError
  185. from aioresponses import aioresponses
  186. @aioresponses()
  187. def test_how_to_throw_an_exception(m, test_client):
  188. loop = asyncio.get_event_loop()
  189. session = ClientSession()
  190. m.get('http://example.com/api', exception=HttpProcessingError('test'))
  191. # calling
  192. # loop.run_until_complete(session.get('http://example.com/api'))
  193. # will throw an exception.
  194. **aioresponses allows to use callbacks to provide dynamic responses**
  195. .. code:: python
  196. import asyncio
  197. import aiohttp
  198. from aioresponses import CallbackResult, aioresponses
  199. def callback(url, **kwargs):
  200. return CallbackResult(status=418)
  201. @aioresponses()
  202. def test_callback(m, test_client):
  203. loop = asyncio.get_event_loop()
  204. session = ClientSession()
  205. m.get('http://example.com', callback=callback)
  206. resp = loop.run_until_complete(session.get('http://example.com'))
  207. assert resp.status == 418
  208. **aioresponses can be used in a pytest fixture**
  209. .. code:: python
  210. import pytest
  211. from aioresponses import aioresponses
  212. @pytest.fixture
  213. def mock_aioresponse():
  214. with aioresponses() as m:
  215. yield m
  216. Features
  217. --------
  218. * Easy to mock out HTTP requests made by *aiohttp.ClientSession*
  219. License
  220. -------
  221. * Free software: MIT license
  222. Credits
  223. -------
  224. This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.
  225. .. _Cookiecutter: https://github.com/audreyr/cookiecutter
  226. .. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage