-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
MagicServer: a fake server for testing #2512
Comments
What this server will test if it suppose to always respond with 200? If you want |
@kxepal let's assume I should test my system which integrates with facebook or github. |
@asvetlov You can just simply mock all requests responses, defining what more-or-less Facebook will return to you and how your client would react on that. Same result, but less to code and no network round trips (faster tests in other words). Moreother, this way will allow you to make tests against exact real Facebook responces and track down regressions. With fake server I'm not sure how you'll do the same. |
There is https://github.com/pnuckowski/aioresponses which is clone of https://github.com/getsentry/responses but for aiohttp. @aioresponses()
def test_http_headers(m):
loop = asyncio.get_event_loop()
session = aiohttp.ClientSession()
m.post( 'http://facebok.com', payload=dict(), headers=heders)
resp = loop.run_until_complete(session.post('http://example.com')) Agree with @kxepal , mocking looks like better approach. Side note: I implemented fake server few times to test download and retry logic. Basically I had aiohttp server and simulated different failures:
|
+1 for mocks over fake server. Doing a fake server you have to keep maintaining it as a new piece of software, services you connect to keep evolving and implementing all cases like timeouts, bad responses, different status is hard with fake servers while with mocks usually is couple of lines |
Quite the reverse, aioresponse is a separate piece of software which is never going to exactly match a real response. Generally running a real aiohttp server guarantees realistic responses. Because you're communicating with a real (if very close) server. Personally I find creating and using a real server very quick and haven't had issues at all with maintaining them ever as aiohttp has developed. The whole point in MagicServer is that it would make using a server to test requests a one-liner. |
Could you please show (as concept) how it would, because these two statements looks like conflicting for me (fake server vs mock one). |
I achieve the same with mocks (I don't use aioresponses, just asynctest). Anyway as @kxepal comments maybe a practical example would help to understand |
MagicServer works as specification, as spec evolves server impl changes. then it is easy to make sure software is compatible with spec. Mock solves different pproblem. I think, excessive mock usage is bad idea. |
Good example is sockjs library, it has sockjs-protocol.py tests, so it is very easy to create server implementation |
Far from perfect, but hopefully this demonstrates how it would work: import pytest
import aiohttp
from aiohttp import web
@web.middleware
async def logging_middleware(request, handler):
try:
r = await handler(request)
except web.HTTPException as e:
request.app['request_log'].append(f'{request.method} {request.path_qs} > {e.status}')
raise
except Exception:
request.app['request_log'].append(f'{request.method} {request.path_qs} > 500')
raise
else:
request.app['request_log'].append(f'{request.method} {request.path_qs} > {r.status}')
return r
def create_magic_app():
app = web.Application(middlewares=[logging_middleware])
app['request_log'] = []
return app
@pytest.fixture
def magic_server(loop, test_server):
app = create_magic_app()
server = loop.run_until_complete(test_server(app))
server.url = f'http://localhost:{server.port}'
return server
async def foobar(endpoint):
"""
This is the function to test
"""
async with aiohttp.ClientSession() as session:
async with session.get(endpoint) as r:
t = await r.text()
if 'hello' in t:
async with session.get(endpoint + 'whatever/') as r:
if r.status == 409:
return 'foo'
else:
return 'bar'
async def test_index(request):
...
return web.Response(text='hello')
async def test_foobar(magic_server):
# FIXME: the following won't work yet, would need someway to freeze the app on first request
# or add endpoints after freezing
# add_get, add_post, add_route work like app.router.* methods, but allow responses as arguments
magic_server.add_get('/', test_index) # will call test_index and return result
magic_server.add_post('/whatever/', web.HTTPConflict()) # will just return 409
v = await foobar(server.url)
assert v == 'foo'
assert magic_server.app['request_log'] == [
'GET / > 200',
'POST /whatever/ > 409',
] |
A few notes:
|
I still feel mocking is way simpler
Also faster since there is no need to setup and start app for every test and even if you would make the server fixture session scoped then you would have risks of being stateful during the tests run. |
I run thousands of tests with test scoped server, the time taken is tiny.
…On 13 Nov 2017 22:55, "Manuel Miranda" ***@***.***> wrote:
I still feel mocking is way simpler
with patch('my_module.ClientSession.get', return_value=ResponseLikeObject):
await do_your_request()
Also faster since there is no need to setup and start app for every test
and even if you would make the server fixture session scoped then you would
have risks of being stateful during the tests run.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#2512 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AD2jGU3NPJMU5nBC8a8YyufoYupbOZDRks5s2MjagaJpZM4Qa3gZ>
.
|
In that case I guess its more of a personal opinion of what to use. Its not like its going to force anyone to use it so no strong opinion on whether it makes to officially to aiohttp or not |
Sorry for intrusion, but, given I've spent some time converting https://github.com/aio-libs/aiohttp/blob/master/examples/fake_server.py to tests, I'll leave a gist for newbies here https://gist.github.com/ambivalentno/e311ea008d05938ac5dd3048ce76e3d1 Also, I have to note that if you've got 10 apis with similar logic, but different urls/ response schemas, it's much easier to write an abstract test server to encapsulate their logic and next add routes and serialization only. imho. |
Like MagicMock but for testing requests:
Thoughts/ideas?
The text was updated successfully, but these errors were encountered: