I played a bit arround with the example in the aiohttp docs about unitttesting to find out what is going on in the example and how it works. And I think I still missunderstand some things.
I need to "simulate" the download of xml or html files from URLs. But the example code is about GET
method because it does router.add_get()
. But there is not router.add_url()
or something like that.
So is wrong in my understanding?
The error is
$ python3 -m unittest org.py
E
======================================================================
ERROR: test_example (org.MyAppTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python3.9/dist-packages/aiohttp/test_utils.py", line 439, in setUp
self.app = self.loop.run_until_complete(self.get_application())
File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/home/user/share/work/aiotest/org.py", line 16, in get_application
app.router.add_get('https://stackoverflow.com', hello)
File "/usr/local/lib/python3.9/dist-packages/aiohttp/web_urldispatcher.py", line 1158, in add_get
resource = self.add_resource(path, name=name)
File "/usr/local/lib/python3.9/dist-packages/aiohttp/web_urldispatcher.py", line 1071, in add_resource
raise ValueError("path should be started with / or be empty")
ValueError: path should be started with / or be empty
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
The example code
#!/usr/bin/env python3
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from aiohttp import web, ClientSession
class MyAppTestCase(AioHTTPTestCase):
async def get_application(self):
"""
Override the get_app method to return your application.
"""
async def hello(request):
return web.Response(text='Hello')
app = web.Application()
app.router.add_get('https://stackoverflow.com', hello)
return app
# the unittest_run_loop decorator can be used in tandem with
# the AioHTTPTestCase to simplify running
# tests that are asynchronous
@unittest_run_loop
async def test_example(self):
async with ClientSession() as session:
async with session.get('https://stackoverflow.com') as resp:
assert resp.status == 200
text = await resp.text()
assert 'Hello' in text
EDIT: My Python is 3.9.2 (default, Feb 28 2021, 17:03:44) [GCC 10.2.1 20210110]
and aiohttp is `3.7.4.post0' - both from Debian 11 (stable) repository.
You can't mock a specific address with aiohttp.web.Application()
routers. It expect you to declare routes relatively to the root of your application like on an example you mentioned:
class MyAppTestCase(AioHTTPTestCase):
async def get_application(self):
"""
Override the get_app method to return your application.
"""
async def hello(request):
return web.Response(text='Hello, world')
app = web.Application()
app.router.add_get('/', hello)
return app
You should either test an application that you create in get_application
method using self.client
reference and use relative paths:
@unittest_run_loop
async def test_example(self):
resp = await self.client.request("GET", "/")
assert resp.status == 200
text = await resp.text()
assert "Hello, world" in text
Or (what you probably actually want) use responses library:
@responses.activate
def test_simple():
responses.add(responses.GET, 'https://stackoverflow.com',
body='Hello', status=200)