Package: httpretty_fixtures
Fixture manager forhttprettyFeatures:Reuse responses across testsAllows maintaining state between requestsSee theExamples section for a demonstrationAccess past request informationOn per-fixture basisAcross all fixturesThis was written to solve communicating to an Elasticsearch during tests. For our usage,mockdidn’t scale well and placinghttprettyfixtures on our base test case was impratical. To solve this, we wrote a fixture manager,httpretty-fixtures.Getting StartedInstall the module with:pip install httpretty_fixtures# Load in our dependenciesimportjsonimportunittestimporthttpretty_fixturesimportrequests# Set up our fixture managerclassFakeElasticsearch(httpretty_fixtures.FixtureManager):@httpretty_fixtures.get('http://localhost:9200/my_index/my_document/my_id')defes_index(self,request,uri,res_headers):return(200,res_headers,json.dumps({'_index':'my_index','_type':'my_document','_id':'my_id','_version':1,'found':True,}))# Define our testsclassMyTestCase(unittest.TestCase):@FakeElasticsearch.run(['es_index'])deftest_retrieve_from_es(self,fake_elasticsearch):"""Verify we can retrieve an item from Elasticsearch"""# Make our request and verify we hit Elasticsearchres=requests.get('http://localhost:9200/my_index/my_document/my_id?first')self.assertEqual(res.status_code,200)self.assertEqual(res.json()['_index'],'my_index')# Make a second request for demonstration purposesrequests.get('http://localhost:9200/my_index/my_document/my_id?second')# Introspect our request received on `FakeElasticsearch`fixture=fake_elasticsearch.es_indexself.assertEqual(fixture.first_request.path,'/my_index/my_document/my_id?first')self.assertEqual(fixture.last_request.path,'/my_index/my_document/my_id?second')self.assertEqual(len(fixture.requests),2)self.assertEqual(fixture.requests[0].path,'/my_index/my_document/my_id?first')self.assertEqual(fixture.requests[1].path,'/my_index/my_document/my_id?second')# Access request information from all `httpretty` requestsself.assertEqual(httpretty_fixtures.first_request().path,'/my_index/my_document/my_id?first')self.assertEqual(httpretty_fixtures.last_request().path,'/my_index/my_document/my_id?second')self.assertEqual(len(httpretty_fixtures.requests()),2)self.assertEqual(httpretty_fixtures.requests()[0].path,'/my_index/my_document/my_id?first')self.assertEqual(httpretty_fixtures.requests()[1].path,'/my_index/my_document/my_id?second')Documentationhttpretty-fixturesexportsFixtureManager,get,put,post,delete,head,patch,options,connect,first_request,last_request, andrequestsas methods/variables.We will refer to the package ashttpretty_fixtures.FixtureManager()Class for setting up a set of fixtures on. This should be inherited from into another class with its own set of fixtures.classFakeElasticsearch(httpretty_fixtures.FixtureManager):@httpretty_fixtures.get('http://localhost:9200/my_index/my_document/my_id')defes_index(self,request,uri,res_headers):return(200,res_headers,json.dumps({'content':'goes here'}))fixture_manager.run(fixtures)Decorator to run a set of fixtures during a functionfixtureslist- Names of fixture functions to run*str- Name of fixtures function to runWe will pass in the server instance as an argument to the decorated function. From the server, we canaccess per-instance fixture information and requests.classFakeElasticsearch(httpretty_fixtures.FixtureManager):@httpretty_fixtures.get('http://localhost:9200/my_index/my_document/my_id')defes_index(self,request,uri,res_headers):return(200,res_headers,json.dumps({}))classMyTestCase(unittest.TestCase):# The `es_index` fixture will be live for all of this test case@FakeElasticsearch.run(['es_index'])deftest_retrieve_from_es(self,fake_elasticsearch):"""Verify we can retrieve an item from Elasticsearch"""# Make our request and verify we hit Elasticsearchres=requests.get('http://localhost:9200/my_index/my_document/my_id')fixture_manager.start(fixtures)Start running HTTPretty with a set of fixturesfixtureslist- Names of fixture functions to run*str- Name of fixtures function to runReturns:Returns a running instance offixture_manager. This can be used toaccess fixtures and their request information..start()will run HTTPretty indefinitely until.stop()is called.fixture_manager.stop()Stop a running instance of HTTPretty. This should always be run at some point after a.start()httpretty_fixtures.{verb}(*register_uri_args, **register_uri_kwargs)Decorator to register a fixture function under an HTTP verbThis is a summary for all possible HTTP verbs:@httpretty_fixtures.get()@httpretty_fixtures.put()@httpretty_fixtures.post()@httpretty_fixtures.delete()@httpretty_fixtures.head()@httpretty_fixtures.patch()@httpretty_fixtures.options()@httpretty_fixtures.connect()Each of these verbs functions passes its arguments/keyword arguments toHTTPretty's register_uri` function.If there are any arguments you want to apply to your fixture with respect toHTTPretty, this is how to do it.https://github.com/gabrielfalcao/HTTPretty/tree/0.8.3#usage@httpretty_fixtures.get("http://underdog.io/")Function signaturehttpretty_fixturesleverages the dynamic callback functionality ofhttpretty:https://github.com/gabrielfalcao/HTTPretty/tree/0.8.3#dynamic-responses-through-callbacksAs a result, we expect our decorator to receive a function that matches the following signature:@httpretty_fixtures.get("http://underdog.io/")defrequest_handler(self,request,uri,res_headers):res_tuple=(status_code,res_headers,body)returnres_tuple# Example@httpretty_fixtures.get("http://underdog.io/")defhello(self,request,uri,res_headers):return(200,res_headers,'Hello World!')The signature is as follows:request_handlerfunction- Handler for our request callbackselfobject- Instance of class extended on top of forFixtureManageruriobject- Information about incoming requestStructure is managed byhttprettyMore info can be read from the source codehttps://github.com/gabrielfalcao/HTTPretty/blob/0.8.3/httpretty/core.py#L615-L647res_headersobject- Default response headers to provide to requestThese should be modified and/or passed through in theres_tupleres_tupletuple- Collection of information for our response[0]int- Status code to provide for responseFor example, 200 would be a 200 HTTP status code[1]object- Modified or provided set of headers provided as a parameter[2]str- Response body for our requestIn the example above, we replied with'Hello World!'but this could be JSON, XML, or whatever you needFunction attributeshttpretty_fixturesprovides helper properties to access past request information. For the sake of reference, we will refer to a fixture asfixturefixture.first_request- Accesses first request received by fixture in our.run()current instanceIf no request was received, then this will beNonefixture.last_request- Accesses last request received by fixture in our.run()current instanceIf no request was received, then this will beNonefixture.requests- List of all requests received by our fixtureAfixtureshould be accessible via the returned server from our.run()decorator or.start()classMyTestCase(unittest.TestCase):# The `es_index` fixture will be live for all of this test case@FakeElasticsearch.run(['es_index'])deftest_retrieve_from_es(self,fake_elasticsearch):# Access our `fixture` and its propertiesfake_elasticsearch.es_indexfake_elasticsearch.es_index.first_requestfake_elasticsearch.es_index.last_requestfake_elasticsearch.es_index.requestshttpretty_fixtures.first_request()Alias to access the first request received byHTTPretty.Warning:If you are usingHTTPrettyin other locations, then this will register those requests as well.httpretty_fixtures.last_request()Alias to access the last request received byHTTPretty.Warning:If you are usingHTTPrettyin other locations, then this will register those requests as well.httpretty_fixtures.requests()Alias to access all requests received byHTTPretty.Warning:If you are usingHTTPrettyin other locations, then this will register those requests as well.ExamplesPreserving state between requestsIn this example, we will count between multiple requests to indicate that state is being preserved.# Load in our dependenciesimportunittestimporthttpretty_fixturesimportrequests# Set up our fixture managerclassCounterServer(httpretty_fixtures.FixtureManager):def__init__(self):self.count=0super(CounterServer,self).__init__()@httpretty_fixtures.get('http://localhost:9000/')defcounter(self,request,uri,res_headers):self.count+=1return(200,res_headers,str(self.count))# Define our testsclassMyTestCase(unittest.TestCase):@CounterServer.run(['counter'])deftest_counter_state(self,counter_server):"""Verify we can preserve state between requests"""# Make our first request and verify its countres=requests.get('http://localhost:9000/')self.assertEqual(res.status_code,200)self.assertEqual(res.text,'1')# Make our second request and verify its countres=requests.get('http://localhost:9000/')self.assertEqual(res.status_code,200)self.assertEqual(res.text,'2')@CounterServer.run(['counter'])deftest_counter_alternate_state(self,counter_server):"""Verify state is not maintained between separate `FixtureManager.run()'s`"""res=requests.get('http://localhost:9000/')self.assertEqual(res.status_code,200)self.assertEqual(res.text,'1')ContributingIn lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Test vianosetests.LicenseCopyright (c) 2015 Underdog.ioLicensed under the MIT license.