Package: aresponses
aresponsesan asyncio testing server for mocking external servicesFeaturesFast mocks using actual network connectionsallows mocking some types of network issuesuse regular expression matching for domain, path, method, or bodyworks with https requests as well (by switching them to http requests)works with callablesUsageAdd routes and responses via thearesponses.addmethod:defadd(host_pattern=ANY,path_pattern=ANY,method_pattern=ANY,response="",*,route=None,body_pattern=ANY,mmatch_querystring=False,repeat=1)When a request is received the first matching response will be returned
and removed from the routing table.  Theresponseargument can be
either a string, Response, dict, or list.  Usearesponses.Responsewhen you need to do something more complex.Note that version >=2.0 requires explicit assertions!@pytest.mark.asyncioasyncdeftest_simple(aresponses):aresponses.add("google.com","/api/v1/","GET",response="OK")aresponses.add('foo.com','/','get',aresponses.Response(text='error',status=500))asyncwithaiohttp.ClientSession()assession:asyncwithsession.get("http://google.com/api/v1/")asresponse:text=awaitresponse.text()asserttext=="OK"asyncwithsession.get("https://foo.com")asresponse:text=awaitresponse.text()asserttext=="error"aresponses.assert_plan_strictly_followed()AssertionsIn aresponses 1.x requests that didn't match a route stopped the event
loop and thus forced an exception.  In aresponses >2.x it's required to
make assertions at the end of the test.There are three assertions functions provided:aresponses.assert_no_unused_routesRaisesUnusedRouteErrorif all
the routes defined were not used up.aresponses.assert_called_in_order- RaisesUnorderedRouteCallErrorif the routes weren't called in the order they were defined.aresponses.assert_all_requests_matched- RaisesNoRouteFoundErrorif any requests were made that didn't match to a route.  It's likely
but not guaranteed that your code will throw an exception in this
situation before the assertion is reached.Instead of calling these individually,it's recommended to callaresponses.assert_plan_strictly_followed()at the end of each test as
it runs all three of the above assertions.Regex and Repeathost_pattern,path_pattern,method_patternandbody_patternmay
be either strings (exact match) or regular expressions.The repeat argument permits a route to be used multiple times.If you want to just blanket mock a service, without concern for how many
times its called you could set repeat to a large number and not callaresponses.assert_plan_strictly_followedorarespones.assert_no_unused_routes.@pytest.mark.asyncioasyncdeftest_regex_repetition(aresponses):aresponses.add(re.compile(r".*\.?google\.com"),response="OK",repeat=2)asyncwithaiohttp.ClientSession()assession:asyncwithsession.get("http://google.com")asresponse:text=awaitresponse.text()asserttext=="OK"asyncwithsession.get("http://api.google.com")asresponse:text=awaitresponse.text()asserttext=="OK"aresponses.assert_plan_strictly_followed()Json ResponsesAs a convenience, if a dict or list is passed toresponsethen it will
create a json response. Aaiohttp.web_response.json_responseobject
can be used for more complex situations.@pytest.mark.asyncioasyncdeftest_json(aresponses):aresponses.add("google.com","/api/v1/","GET",response={"status":"OK"})asyncwithaiohttp.ClientSession()assession:asyncwithsession.get("http://google.com/api/v1/")asresponse:assert{"status":"OK"}==awaitresponse.json()aresponses.assert_plan_strictly_followed()Custom HandlerCustom functions can be used for whatever other complex logic is
desired. In example below the handler is set to repeat infinitely
and always return 500.importmath@pytest.mark.asyncioasyncdeftest_handler(aresponses):defbreak_everything(request):returnaresponses.Response(status=500,text=str(request.url))aresponses.add(response=break_everything,repeat=math.inf)asyncwithaiohttp.ClientSession()assession:asyncwithsession.get("http://google.com/api/v1/")asresponse:assertresponse.status==500PassthroughPassaresponses.passthroughinto the response argument to allow a
request to bypass mocking.aresponses.add('httpstat.us','/200','get',aresponses.passthrough)Inspecting historyHistory of calls can be inspected viaaresponses.historywhich returns
the namedTupleRoutingLog(request, route, response)@pytest.mark.asyncioasyncdeftest_history(aresponses):aresponses.add(response=aresponses.Response(text="hi"),repeat=2)asyncwithaiohttp.ClientSession()assession:asyncwithsession.get("http://foo.com/b")asresponse:awaitresponse.text()asyncwithsession.get("http://bar.com/a")asresponse:awaitresponse.text()assertlen(aresponses.history)==2assertaresponses.history[0].request.host=="foo.com"assertaresponses.history[1].request.host=="bar.com"assert"Route("inrepr(aresponses.history[0].route)aresponses.assert_plan_strictly_followed()Context manager usageimportaiohttpimportpytestimportaresponses@pytest.mark.asyncioasyncdeftest_foo(event_loop):asyncwitharesponses.ResponsesMockServer(loop=event_loop)asarsps:arsps.add('foo.com','/','get','hi there!!')arsps.add(arsps.ANY,'/','get',arsps.Response(text='hey!'))asyncwithaiohttp.ClientSession(loop=event_loop)assession:asyncwithsession.get('http://foo.com')asresponse:text=awaitresponse.text()asserttext=='hi'asyncwithsession.get('https://google.com')asresponse:text=awaitresponse.text()asserttext=='hey!'working withpytest-aiohttpIf you need to use aresponses together with pytest-aiohttp, you should re-initialize main aresponses fixture withloopfixturefromaresponsesimportResponsesMockServer@pytest.fixtureasyncdefaresponses(loop):asyncwithResponsesMockServer(loop=loop)asserver:yieldserverIf you're trying to use theaiohttp_clienttest fixture then you'll need to mock out the aiohttploopfixture
instead:@pytest.fixturedefloop(event_loop):"""replace aiohttp loop fixture with pytest-asyncio fixture"""returnevent_loopContributingDev environment setupinstall pyenv and pyenv-virtualenv- Makes it easy to install specific versions of python and switch between them. Make sure you install the virtualenv bash hookgit clonethe repo andcdinto it.make init- installs proper version of python, creates the virtual environment, activates it and installs all the requirementsSubmitting a feature requestgit checkout -b my-feature-branchmake some cool changesmake autoformatmake testmake lintcreate pull requestUpdating package on pypimake deployChangelog3.0.0fix: start usingasyncio.get_running_loop()instead ofevent_loopper the error:PytestDeprecationWarning: aresponses is asynchronous and explicitly requests the "event_loop" fixture. 
Asynchronous fixtures and test functions should use "asyncio.get_running_loop()" instead.drop support for python 3.6add comprehensive matrix testing of all supported python and aiohttp versionstighten up the setup.py requirements2.1.6fix: incorrect pytest plugin entrypoint name (#72)2.1.5support asyncio_mode = strict (#68)2.1.4fix: don't assume utf8 request contents2.1.3accidental no-op release2.1.2documentation: add pypi documentation2.1.1bugfix: RecursionError when aresponses is used in more than 1000 tests (#63)2.1.0feature: add convenience methodadd_local_passthroughbugfix: fix https subrequest mocks. support aiohttp_client compatibility2.0.2bugfix: ensure request body is available in history2.0.0Warning! Breaking Changes!breaking change: require explicit assertions for test failuresfeature: autocomplete works in intellij/pycharmfeature: can match on body of requestfeature: store calls madefeature: repeated responsesbugfix: no longer stops event loopfeature: if dict or list is passed intoresponse, a json response
will be generated1.1.2make passthrough feature work with binary data1.1.1regex fix for Python 3.7.01.1.0Added passthrough option to permit live network callsAdded example of using a callable as a response1.0.0Added an optionalmatch_querystringargument that lets you match on querystring as wellContributorsBryce Drennan, CircleUparesponses@brycedrennan.comMarco Castelluccio, Mozillamcastelluccio@mozilla.comJesse Vogt, CircleUpjesse.vogt@gmail.comPavol Vargovcik, Kiwi.compavol.vargovcik@gmail.com