Chapter 8. Testing and Deploying an API with Flask
In this chapter, we will configure, write, and execute unit tests and learn a few things related to deployment. We will:
Set up unit tests
Create a database for testing
Write a first round of unit tests
Run unit tests and check testing coverage
Improve testing coverage
Understand strategies for deployments and scalability
We will use nose2
to make it easier to discover and run unit tests. We will measure test coverage, and therefore, we will install the necessary package to allow us to run coverage with nose2
. First, we will install the nose2
and cov-core
packages in our virtual environment. The cov-core
package will allow us to measure test coverage with nose2
. Then, we will create a new PostgreSQL database that we will use for testing. Finally, we will create the configuration file for the testing environment.
Make sure you quit the Flask's development server. Remember that you just need to press
Ctrl
+
C
in the terminal or the Command Prompt window in which it is running. We just need to run the following command to install the nose2
package:
pip install nose2
The last lines of the output will indicate that the django-nose
package has been successfully installed.
Collecting nose2
Collecting six>=1.1 (from nose2)
Downloading six-1.10.0-py2.py3-none-any.whl
Installing collected...
Writing a first round of unit tests
Now, we will write a first round of unit tests. Specifically, we will write unit tests related to the user and message category resources: UserResource
, UserListResource
, CategoryResource
, and CategoryListResource
. Create a new tests
sub-folder within the api
folder. Then, create a new test_views.py
file within the new api/tests
sub-folder. Add the following lines, that declare many import
statements and the first methods for the InitialTests
class. The code file for the sample is included in the restful_python_chapter_08_01
folder:
from app import create_app
from base64 import b64encode
from flask import current_app, json, url_for
from models import db, Category, Message, User
import status
from unittest import TestCase
class InitialTests(TestCase):
def setUp(self):
self.app = create_app('test_config')
self.test_client = self.app.test_client()
self.app_context...
Running unit tests with nose2 and checking testing coverage
Now, run the following command to create all the necessary tables in our test database and use the nose2
test running to execute all the tests we created. The test runner will execute all the methods for our InitialTests
class that start with the test_
prefix and will display the results.
Tip
The tests won't make changes to the database we have been using when working on the API. Remember that we configured the test_messages
database as our test database.
Remove the api.py
file we created in the previous chapter from the api
folder because we don't want the tests coverage to take into account this file. Go to the api
folder and run the following command within the same virtual environment that we have been using. We will use the -v
option to instruct nose2
to print test case names and statuses. The --with-coverage
option turns on test coverage reporting generation:
nose2 -v --with-coverage
The following lines show the sample output...
Improving testing coverage
Now, we will write additional unit tests to improve the testing coverage. Specifically, we will write unit tests related to messages and users. Open the existing api/tests/test_views.py
file and insert the following lines after the last line, within the InitialTests
class. We need a new import
statement and we will declare the new PlayerTests
class. The code file for the sample is included in the restful_python_chapter_08_02
folder:
def create_message(self, message, duration, category):
url = url_for('api.messagelistresource', _external=True)
data = {'message': message, 'duration': duration, 'category': category}
response = self.test_client.post(
url,
headers=self.get_authentication_headers(self.test_user_name,
self.test_user_password),
data=json.dumps(data))
return response
def test_create_and_retrieve_message(self...
Understanding strategies for deployments and scalability
Flask is a lightweight microframework for the Web. However, as happens with Django, one of the biggest drawbacks related to Flask and Flask-RESTful is that each HTTP request is blocking. Thus, whenever the Flask server receives an HTTP request, it doesn't start working on any other HTTP requests in the incoming queue until the server sends the response for the first HTTP request it received.
We used Flask to develop a RESTful Web Service. They key advantage of these kind of Web Services is that they are stateless, that is, they shouldn't keep a client state on any server. Our API is a good example of a stateless RESTful Web Service with Flask and Flask RESTful. Thus, we can make the API run on as many servers as necessary to achieve our scalability goals. Obviously, we must take into account that we can easily transform the database server in our scalability bottleneck.
Tip
Nowadays, we have a huge number of cloud-based alternatives to...
In this chapter, we set up a testing environment. We installed nose2 to make it easy to discover and execute unit tests, and we created a new database to be used for testing. We wrote a first round of unit tests, measured test coverage, and then we wrote additional unit tests to improve test coverage. Finally, we understood many considerations for deployment and scalability.
Now that we have built a complex API with Flask combined with Flask RESTful, and we tested it, we will move to another popular Python Web framework, Tornado, which is what we are going to discuss in the next chapter.