How to test httpx with trio and respx
See original GitHub issueHi Lundberg, I am working on a project on httpx using trio async libray. Following your documentation, I ended up with a test like this:
@pytest.mark.trio
async def test_should_do_something(trio_tmp_path):
async with respx.mock:
async with httpx.AsyncClient() as client:
analyser = RobotsAnalyzer(
user_agent='Mozilla/5.0',
robots_cache=trio_tmp_path,
http_client=client,
robots_mapping_lock=robots_mapping_lock_mock,
delay_mapping_lock=delay_mapping_lock_mock
)
respx.get('/robots.txt', content=httpx.ConnectTimeout())
assert await analyser.can_fetch('http://example.com/path') is False
but I have this weird error, I don’t know if there is a tip to avoid the issue.
value = <trio.Nursery object at 0x051E4EB0>
async def yield_(value=None):
> return await _yield_(value)
C:\Users\rolla\AppData\Local\pypoetry\Cache\virtualenvs\scalpel-HJDWBcSE-py3.8\lib\site-packages\async_generator\_impl.py:106:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
C:\Users\rolla\AppData\Local\pypoetry\Cache\virtualenvs\scalpel-HJDWBcSE-py3.8\lib\site-packages\async_generator\_impl.py:99: in _yield_
return (yield _wrap(value))
test_robots.py:104: in test_should_return_false_when_host_does_not_exist
assert await analyser.can_fetch('http://example.com/path') is False
..\..\scalpel\trionic\robots.py:53: in can_fetch
response = await self._http_client.get(f'{robots_url}')
C:\Users\rolla\AppData\Local\pypoetry\Cache\virtualenvs\scalpel-HJDWBcSE-py3.8\lib\site-packages\httpx\_client.py:1224: in get
return await self.request(
C:\Users\rolla\AppData\Local\pypoetry\Cache\virtualenvs\scalpel-HJDWBcSE-py3.8\lib\site-packages\httpx\_client.py:1085: in request
response = await self.send(
C:\Users\rolla\AppData\Local\pypoetry\Cache\virtualenvs\scalpel-HJDWBcSE-py3.8\lib\site-packages\respx\mocks.py:162: in unbound_async_send
return await self.__AsyncClient__send__spy(client, request, **kwargs)
C:\Users\rolla\AppData\Local\pypoetry\Cache\virtualenvs\scalpel-HJDWBcSE-py3.8\lib\site-packages\respx\mocks.py:530: in __AsyncClient__send__spy
with self._patch_dispatcher(client.dispatch, request) as capture:
C:\Users\rolla\AppData\Local\Programs\Python\Python38-32\lib\contextlib.py:113: in __enter__
return next(self.gen)
C:\Users\rolla\AppData\Local\pypoetry\Cache\virtualenvs\scalpel-HJDWBcSE-py3.8\lib\site-packages\respx\mocks.py:472: in _patch_dispatcher
httpx_mock, pattern, response = self._match(request)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <respx.mocks.HTTPXMock object at 0x051363E8>
request = <Request('GET', 'http://example.com/robots.txt')>
def _match(
self, request: Request
) -> typing.Tuple[
"HTTPXMock", typing.Optional[RequestPattern], typing.Optional[ResponseTemplate]
]:
used_mock = self
matched_pattern: typing.Optional[RequestPattern] = None
matched_pattern_index: typing.Optional[int] = None
response: typing.Optional[ResponseTemplate] = None
# Iterate all started mockers and their patterns
for httpx_mock in self._mocks:
patterns = httpx_mock._patterns
for i, pattern in enumerate(patterns):
match = pattern.match(request)
if not match:
continue
if matched_pattern_index is not None:
# Multiple matches found, drop and use the first one
patterns.pop(matched_pattern_index)
break
used_mock = httpx_mock
matched_pattern = pattern
matched_pattern_index = i
if isinstance(match, ResponseTemplate):
# Mock response
response = match
elif isinstance(match, Request):
# Pass-through request
response = None
else:
raise ValueError(
(
"Matched request pattern must return either a "
'ResponseTemplate or a Request, got "{}"'
).format(type(match))
)
if matched_pattern:
break
if matched_pattern is None:
# Assert we always get a pattern match, if check is enabled
allows_unmocked = tuple(m for m in self._mocks if not m._assert_all_mocked)
> assert allows_unmocked, f"RESPX: {request!r} not mocked!"
E AssertionError: RESPX: <Request('GET', 'http://example.com/robots.txt')> not mocked!
My environment
- windows 10
- python3.8
- trio 0.13.0
- pytest-trio 0.5.2
- respx 0.10.1
Best regards
Issue Analytics
- State:
- Created 3 years ago
- Comments:5 (5 by maintainers)
Top Results From Across the Web
User Guide - RESPX
To patch HTTPX , and activate the RESPX router, use the respx.mock ... when using the pytest fixture, decorate the test case with...
Read more >python-trio/general - Gitter
how do you properly develop unit tests for code that calls an external REST API? sorry if this is a bit of a...
Read more >trio + httpx gives TrioDeprecationWarning - Stack Overflow
I raised this in https://github.com/encode/httpx/discussions/2409. To silence the warning: import warnings from trio import ...
Read more >Setting up Python Projects: Part III | by Johannes Schmidt
Because we use httpx, we need to mock the response from the HTTP call (https://pokeapi.co/api). ... poetry add --group test respx pytest-asyncio trio....
Read more >pytest-trio 0.7.0 - PythonFix.com
Pytest plugin for trio. ... GitHub Repo: https://github.com/python-trio/pytest-trio. Classifiers. Software Development/Testing; System/Networking ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Hi lundberg, thank you for the tip. I don’t really know where I made a mistake but re-using your last example works for me.
Again thanks 😃
I re-read your issue and I think I was to fast writing my last answer 😉
When configuring the respx mock object with
base_url
we need to add the request patterns to the context manager instance.Try this:
…hopes this was the issue and helps you.