Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test_client should accept application object as parameter #1066

Closed
mayurmahajan opened this issue Aug 10, 2016 · 11 comments
Closed

test_client should accept application object as parameter #1066

mayurmahajan opened this issue Aug 10, 2016 · 11 comments
Labels

Comments

@mayurmahajan
Copy link

Long story short

This is not an issue, but a feature improvement request. Per this documentation http://aiohttp.readthedocs.io/en/stable/testing.html test_client accepts a create_app function in it's constructor. It will be cool if test_client accepts application object instead.

This feature improvement is not critical. application object is used by any wsgi server to run a service. similarly this test_client should use an application object to create server/client. It's just more convenient to think and use.

Expected behaviour

instead of

@pytest.fixture
def cli(loop, test_client):
return loop.run_until_complete(test_client(create_app))

if test_client accepts app then

@pytest.fixture
def cli(loop, test_client):
return loop.run_until_complete(test_client(app))

Actual behaviour

Behavior wise nothing changes, it's just the implementation change.

Steps to reproduce

Your environment

@asvetlov
Copy link
Member

Good idea.
Would you provide a Pull Request?
Old functionality should be supported too, we cannot make backward incompatible change without very strong reason.

@asvetlov asvetlov added the good first issue Good for newcomers label Aug 11, 2016
@popravich
Copy link
Member

This can be easily achieved without changes to library:

def test_something(test_client):
    client = await test_client(lambda loop: app)

However allowing to pass application object instead of factory can lead to unexpected and
unpredictable errors -- application (or middlewares) may store some state between tests and so
using same input data in different test may lead to unexpected errors or application can be simply
attached to closed loop.
I'm a bit paranoid about it cause I've already seen such bugs.
So I think we can simply add some lines to docs saying how to pass single app instance to test_client.

@asvetlov
Copy link
Member

@popravich but people will either create app in test method or use a fixture for it.
I pretty sure they will never store an app in global var.
Well, they may do it but we all are adult guys.
Passing app instead of factory is more convenient way of thinking.
At least current design was my first spike when I've tried to use the fixture myself.
I've just missed this point on merge/review during PyCon sprints in Portland.

@popravich
Copy link
Member

I pretty sure they will never store an app in global var.

Should I remind you several discussions with word "global" (remember aiopg global pool, recent aiohttp "how to get global app", etc)?
Besides in examples above I didn't find app to be a fixture )

Anyway, having this feature must require big red warning block in docs saying not to use global app
with test_client.

@asvetlov
Copy link
Member

I can live with a big red warning but really need the functionality.
Just compare:

async def test_1(test_client):
    async def handler(request):
         ...
    def create_app(loop, path, handler):
        app = web.Application(loop=loop)
        app.router.add_get(path, handler)
        return app
    client = test_client(create_app, '/', handler)

with

async def test_2(test_client):
    async def handler(request):
         ...
    app = web.Application(loop=loop)
    app.router.add_get('/', handler)
    client = test_client(app)

I've found the second snipped is more straightforward. Moving create_app for local function to first-class one makes code even worse.

@popravich
Copy link
Member

...and with

async def test_2(test_client):  # missing loop fixture
    async def handler(request):
         ...
    app = web.Application(loop=loop)
    app.router.add_get('/', handler)
    client = test_client(lambda loop: app)

Just 13 chars more and nothing to change in aiohttp

Ok, if you are sure it will work.

@asvetlov
Copy link
Member

asvetlov commented Aug 11, 2016

Jut a simple thought: if test_client(lambda loop: app) is the recommended and the most practical way to use the fixture -- why we need typing lambda loop: everywhere?

@popravich
Copy link
Member

It at least verbose that application factory will receive loop.
Fine, lets make it clear -- test_client can accept application instance,
but it must check that it bound to proper loop.

@asvetlov
Copy link
Member

Perfect! I love this.

@asvetlov
Copy link
Member

Fixed by #1083

@lock
Copy link

lock bot commented Oct 29, 2019

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.

@lock lock bot added the outdated label Oct 29, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants