Hi,
I'm trying to unit-test a simple app I'm creating. Basically, given this code:
async def hello(request):
return web.Response(body=b"Hello, world")
I'd like to simulate a request to the hello function and verify that the response code is 200. I used to do similar things with the Django teat st client but I'm not sure how to do the same thing with aiohttp.web.
I had a look at webtest-aiohttp but I couldn't get it working with recent versions of aiohttp.web.
Thanks!
Hi Andrew,
I was able to write a test and it works great, thanks for the pointer. My understanding is that being able to test is largely dependant on conftest.py setting up the correct environment.
I made a few changes to conftest.py to adapt it to my situation. In your original version, app and request handlers are created on the fly by the testcases, whereas in my case I'm testing an existing app with its own request handlers.
To do so, I changed the loop fixture creator to pick up the event loop from the one I declared in my application:
@pytest.yield_fixture
def loop(request):
from .app import loop
yield loop
and I did the same thing for create_server, to pick up the app from the one I declared instead of creating a new one:
@pytest.yield_fixture
def create_server(loop, unused_port):
app = handler = srv = None
@asyncio.coroutine
def create(*, debug=False, ssl_ctx=None, proto='http'):
nonlocal app, handler, srv
from .app import app #### <--------- THIS CHANGED --------------
port = unused_port()
handler = app.make_handler(debug=debug, keep_alive_on=False)
srv = yield from loop.create_server(handler, '127.0.0.1', port,
ssl=ssl_ctx)
if ssl_ctx:
proto += 's'
url = "{}://127.0.0.1:{}".format(proto, port)
return app, url
yield create
@asyncio.coroutine
def finish():
yield from handler.finish_connections()
yield from app.finish()
srv.close()
yield from srv.wait_closed()
loop.run_until_complete(finish())
After this, I was able to run a test with:
@pytest.mark.run_loop
async def test_hello(create_app_and_client):
app, client = await create_app_and_client()
async with client.get('/') as resp:
assert resp.status == 200
Do you think I'm doing the right thing? While It certainly seems like working, I'm really not sure that this is correct.
Thanks!
I hate global variables like app and loop from your code.
It makes testing awful due lack of test isolation.
But if it floats your boat you may live with global vars.
P.S. Don't close app yield from app.finish() on every test if you use app singleton.
Thanks Andrew,
I have refactored the app to avoid global variables and I'm using the conftest.py code as it is to test my app.
May I suggest that a chapter about testing would be a very helpful documentation addition.
Thanks!
I really want to have a good chapter about writing tests for aiohttp based projects.
Would you start with PR?
I'll help you, sure -- but we need a starting point for the task.
Also I need a feedback from _casual aiohttp users_: I'm _aiohttp developer_ and maybe my experience has lack of requests from newbies.
I have strong feeling that some obvious things from my perspective should be explained and accentuated.
Hi Andrew,
I resumed work on my project based aiohttp.web and unfortunately I don't really feel enough qualified to even start a PR about testing with aiohttp.web. I'm still trying to wrap my head around the conftest.py shipped with aiohttp, but it really requires some deep understanding of both py.test and aiohttp/asyncio which, for the time being, I don't have (It's my first project with both libraries). I'm sorry I'm not able to contribute for now, but as you well say, I'm a _casual user_. And I can tell you that testing is being hard for me :-)
I'll publish a testing support in next aiohttp release.
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a [new issue] for
related bugs.
If you feel like there's important points made in this discussion,
please include those exceprts into that [new issue].
Most helpful comment
I'll publish a testing support in next aiohttp release.