Package: aiomisc-pytest
aiomisc pytest pluginThis package contains a plugin for pytest.Basic usageSimple usage example:asyncdeftest_sample(event_loop):f=event_loop.crete_future()event_loop.call_soon(f.set_result,True)assertawaitfasynchronous fixture example:importasyncioimportpytest@pytest.fixtureasyncdefmy_fixture(loop):awaitasyncio.sleep(0)# Requires python 3.6+yieldIn case you have to save an instance of an async fixture between tests,
the wrong solution is just changing the fixture scope.
But why it wouldn't work? That's because, in the base scenario, theloopfixture creates a new event loop instance per test which will be closed after
test teardown. When you have to use an async fixture any caller ofasyncio.get_event_loop()will get the current event loop instance which
will be closed and the next test will run in another event loop.
So the solution is to redefine theloopfixture with the required scope
and custom fixture with the required scope.importasyncioimportpytestfromaiomiscimportentrypoint@pytest.fixture(scope='module')defloop():withentrypoint()asloop:asyncio.set_event_loop(loop)yieldloop@pytest.fixture(scope='module')asyncdefsample_fixture(loop):yield1LOOP_ID=Noneasyncdeftest_using_fixture(sample_fixture):globalLOOP_IDLOOP_ID=id(asyncio.get_event_loop())assertsample_fixture==1asyncdeftest_not_using_fixture(loop):assertid(loop)==LOOP_IDpytest markersPackage contains some useful markers for pytest:catch_loop_exceptions- uncaught event loop exceptions will failling test.forbid_get_event_loop- forbids callasyncio.get_event_loopduring test case.importasyncioimportpytest@pytest.mark.forbid_get_event_loopasyncdeftest_with_get_loop():defswitch_context():loop=asyncio.get_event_loop()future=loop.create_future()loop.call_soon(future.set_result,True)returnfuturewithpytest.raises(Exception):awaitswitch_context()# Test will be failed@pytest.mark.catch_loop_exceptionsasyncdeftest_with_errors(loop):asyncdeffail():# switch contextawaitasyncio.sleep(0)raiseException()loop.create_task(fail())awaitasyncio.sleep(0.1)returnPassing default contextimportpytest@pytest.fixturedefdefault_context():return{'foo':'bar','bar':'foo',}Testing servicesRedefineservicesfixture in your test module:importaiomiscimportpytestclassSimpleServie(aiomisc.Service):asyncdefstart(self)->None:pass@pytest.fixturedefservices():return[SimpleServie()]Event loop policy overridingimportasyncioimportpytestimporttokioimportuvlooppolicy_ids=('uvloop','asyncio','tokio')policies=(uvloop.EventLoopPolicy(),asyncio.DefaultEventLoopPolicy(),tokio.EventLoopPolicy())@pytest.fixture(params=policies,ids=policy_ids)defevent_loop_policy(request):returnrequest.paramThread pool overridingimportpytestfromaiomisc.thread_poolimportThreadPoolExecutorimportconcurrent.futuresthread_pool_ids=('aiomisc pool','default pool')thread_pool_implementation=(ThreadPoolExecutor,concurrent.futures.ThreadPoolExecutor)@pytest.fixture(params=thread_pool_implementation,ids=thread_pool_ids)defthread_pool_executor(request):returnrequest.paramentrypoint argumentsimportpytest@pytest.fixturedefentrypoint_kwargs()->dict:returndict(log_config=False)aiohttp test clientimportpytestfrommyapp.services.restimportREST@pytest.fixturedefrest_port(aiomisc_unused_port_factory):returnaiomisc_unused_port_factory()@pytest.fixturedefrest_service(rest_port):returnREST(port=rest_port)@pytest.fixturedefservices(rest_service):return[rest_service]@pytest.fixturedefapi_client(api_service):test_srv=TestServer(app=rest_service.app,port=arguments.port,)returnTestClient(test_srv)...TCPProxySimple TCP proxy for emulate network problems. Available as fixturetcp_proxyExamples:importasyncioimporttimeimportpytestimportaiomiscclassEchoServer(aiomisc.service.TCPServer):asyncdefhandle_client(self,reader:asyncio.StreamReader,writer:asyncio.StreamWriter):chunk=awaitreader.read(65534)whilechunk:writer.write(chunk)chunk=awaitreader.read(65534)writer.close()awaitwriter.wait_closed()@pytest.fixture()defserver_port(aiomisc_unused_port_factory)->int:returnaiomisc_unused_port_factory()@pytest.fixture()defservices(server_port,localhost):return[EchoServer(port=server_port,address=localhost)]@pytest.fixture()asyncdefproxy(tcp_proxy,localhost,server_port):asyncwithtcp_proxy(localhost,server_port)asproxy:yieldproxyasyncdeftest_proxy_client_close(proxy):reader,writer=awaitproxy.create_client()payload=b"Hello world"writer.write(payload)response=awaitasyncio.wait_for(reader.read(1024),timeout=1)assertresponse==payloadassertnotreader.at_eof()awaitproxy.disconnect_all()assertawaitasyncio.wait_for(reader.read(),timeout=1)==b""assertreader.at_eof()asyncdeftest_proxy_client_slow(proxy):read_delay=0.1write_delay=0.2# Emulation of asymmetric and slow ISPwithproxy.slowdown(read_delay,write_delay):reader,writer=awaitproxy.create_client()payload=b"Hello world"delta=-time.monotonic()writer.write(payload)awaitasyncio.wait_for(reader.read(1024),timeout=2)delta+=time.monotonic()assertdelta>=read_delay+write_delayasyncdeftest_proxy_client_with_processor(proxy):processed_request=b"Never say hello"# Patching protocol functionsproxy.set_content_processors(# Process data from client to serverlambda_:processed_request,# Process data from server to clientlambdachunk:chunk[::-1],)reader,writer=awaitproxy.create_client()writer.write(b'nevermind')response=awaitreader.read(16)assertresponse==processed_request[::-1]