As mangoHero1 noted, Python comes with SimpleHTTPServer, which can spawn HTTP servers on the fly, in the same process. To have the HTTP client and server in the same process, you'd need to use threading. That would look something like this answer:
https://stackoverflow.com/a/14089457/6084928
I had a very similar use-case to yours and ended up writing an on-demand HTTP server specifically for testing that's based on SimpleHTTPServer. It works backwards from how you might expect a normal HTTP server to work. It accepts any requests, responds based on queued responses, and can later be interrogated as to what the requests look like. Perhaps it can work for your use-case.
https://pypi.python.org/pypi/spoof/
Example usage:
import unittest
import spoof
import thing
class TestThing(unittest.TestCase):
httpd = None
httpd6 = None
@classmethod
def setUpClass(cls):
# X509 certificates can be expensive to generate, so it should be done
# infrequently. Also, creating a new HTTP server instance with a new
# port number for each and every test can starve a system of available
# TCP/IP ports. Because of this, creating an `HTTPServer` instance
# should also be done infrequently, unless the port number is static.
sslContext = spoof.SSLContext.selfSigned()
cls.httpd = spoof.HTTPServer(sslContext=sslContext)
cls.httpd.start()
# IPv6-only, if needed; `HTTPServer` also accepts IPv6 addresses
cls.httpd6 = spoof.HTTPServer6(sslContext=sslContext)
cls.httpd6.start()
@classmethod
def tearDownClass(cls):
cls.httpd.stop()
cls.httpd6.stop()
cls.httpd = None
cls.httpd6 = None
def setUp(self):
# Calling `reset()` suffices to sanitize the HTTP server environment.
self.httpd.reset()
self.httpd.debug = False
self.thing = thing.Thing(self.httpd.address, self.httpd.port)
# or
self.altThing = thing.AltThing(self.httpd.url)
def tearDown(self):
self.thing = None
self.altThing = None
def test_thingUsingSpoof(self):
response1 = [200, [('Content-Type', 'application/json')], '{"id": 1111}']
response2 = [200, [('Content-Type', 'application/json')], '{"id": 2222}']
self.httpd.queueResponse(response1)
self.httpd.queueResponse(response2)
# HTTP debug logging, if needed
self.httpd.debug = True
self.thing.requiringTwoJSONresponses()
lastRequest = self.httpd.requests[-1]
expectedContent = '{"action": "rename", "old": 1111, "new": 2222}'
self.assertEquals(expectedContent, lastRequest.content)