pers consider the structure and the functionality of their application in different situations. Also, writing tests reduces the amount of time a developer needs to spend manually testing their application by enabling them to automate the process.

We’ll set up the test environment using the setUp(self) and tearDown(self) methods. They allow our tests to run independently without being affected by other tests. In this scenario, every time a test runs, we create a Flask test application. We also clean the database after every test in the tearDown(self) method. This ensures that the data stored by the previous test does not affect the next test.

# tests/test_endpoints.py from app import app, db from flask import url_for import unittest class FlaskTodosTest ( unittest . TestCase ): def setUp ( self ): """ Set up test application client """ self .app = app.test_client() self .app.testing = True def tearDown ( self ): """ Clear DB after running tests """ db.todos.remove({})

In this section, we’ll write tests for our endpoints and HTTP methods. We’ll first try to assert that when a user accesses the default homepage(/) they get an OK status(200), and that they are redirected with a 302 status after creating a todo.

# tests/test_endpoints.py class FlaskTodosTest ( unittest . TestCase ): # ..... setup section..... def test_home_status_code ( self ): """ Assert that user successfully lands on homepage """ result = self .app.get( ' / ' ) self .assertEqual(result.status_code, 200 ) def test_todo_creation ( self ): """ Assert that user is redirected with status 302 after creating a todo item """ response = self .app.post( ' /new ' , data = dict ( name = " First todo " , description = " Test todo " ) ) self .assertEqual(response.status_code, 302 ) if __name__ == ' __main__ ' : unittest.main()

The tests can be run using nosetests -v .

Creating the Actual Application

The application uses MongoDB hosted on mlab, which can be changed in the configuration. It provides two routes. The first one, default/index route(/), displays the available todos by rendering a HTML template file. The second route, (/new), accepts only POST requests, and is responsible for saving todo items in the database, and then redirecting the user back to the page with all todos.

# app.py import os from flask import Flask, redirect, url_for, request, render_template from pymongo import MongoClient app = Flask( __name__ ) # Set up database connection. client = MongoClient( " mongodb://username:password@database_url:port_number/db_name " ) db = client[ ' db_name ' ] @app.route ( ' / ' ) def todo (): _items = db.todos.find() items = [item for item in _items] # Render default page template return render_template( ' index.html ' , items = items) @app.route ( ' /new ' , methods = [ ' POST ' ]) def new (): item_doc = { ' name ' : request.form[ ' name ' ], ' description ' : request.form[ ' description ' ] } # Save items to database db.todos.insert_one(item_doc) return redirect(url_for( ' todo ' )) if __name__ == " __main__ " : app.run( host = ' 0.0.0.0 ' , debug = True )

We can then run the application with python app.py , and access it in our browser localhost http://127.0.0.1:5000. If no other port ID is provided, Flask uses port 5000 as the default port. To run the application on a different port, set the port number as follows:

app.run( host = ' 0.0.0.0 ' , port = port_number, debug = True )

Dockerizing the Application

Docker is used to create the application image from the provided Dockerfile configuration. If this is your first time working with Docker, you can follow this step-by-step tutorial to learn more about installing Docker and setting up the environment.

Dockerfile

FROM python:2.7 ADD . /todo WORKDIR /todo EXP