I'm trying to write some unit tests for a flask application i'm building, this is the file that contains the flask application
app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'hello world'
and then the file that contains the tests
tests.py
from unittest import TestCase, main
from app import app
from multiprocessing import Process
import requests
class Test(TestCase):
@classmethod
def setUpClass(cls):
cls.hostname = 'http://localhost:8000'
with app.app_context():
p = Process(target=app.run, kwargs={'port': 8000})
p.start()
cls.p = p
def test_options(self):
# print(self.p.is_alive()) # returns True but requests doesn't connect
result = requests.post(self.hostname).text
self.assertEqual(result, 'hello world')
@classmethod
def tearDownClass(cls):
cls.p.terminate() # works fine if i comment it out
pass
if __name__ == '__main__':
main()
I came up with an idea to use the requests
module to test the application instead of the test_client
that comes with flask.
From my understanding of the unittest module,
The setUpClass
method is called once, that creates a new process and starts the application.
After that i'm free to run various tests with request.post
or request.get
.
Then at the end of the day, when all the tests have been run tearDownClass
is supposed to terminate the process.
When i try to run the tests this is what i get (The stacktrace is actually longer than this, but it all boils down to this)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=5000): Max retries exceeded with url: / (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7faeeba183c8>: Failed to establish a new connection: [Errno 111] Connection refused',))
Because the flask process doesn't start and requests is unable to connect to localhost via port 8000.
but the strange part is if i comment out cls.p.terminate
everything works properly and the test passes, the only problem is that i won't be able to kill the flask process again.
I know i can make the process daemonic or use the test_client
like this:
class Test(TestCase):
@classmethod
def setUpClass(cls):
cls.hostname = 'http://localhost:8000'
with app.app_context():
app.config['TESTING'] = True
cls.app = app.test_client()
def test_options(self):
# print(self.p.is_live())
result = self.app.get().data
self.assertEqual(result, b'hello world')
and just move on with my life, but i really want to understand why my code doesn't work when i try to kill the process when i'm tearing down the test suite.
I've tried to use pdb
to debug, but for some reason i don't know my terminal gets messed up when i try to type anything in the pdb prompt (Some letters don't show up in the terminal as i type, but when i hit enter i discover that the letters were actually there but were not visible, E.g to type print
i might end up having prrrinnnttt
because r
and t
refused to show up when i was pressing them)