Unittesting an app - unit-testing

I'm trying to run a simple unit-test for a restful app I'm creating. The server runs perfectly and displays the json data. I'm looking for a test that confirms that the json data is a 'GET' request or confirms a say a 200 response status code
below is my directory structure
├── MealAPP
├── app
│ ├── __init__.py
│ └── models.py
├── instance
│ ├── __init__.py
│ └── config.py
├── manage.py
├── requirements.txt
├── run.py
└── test_mealapp.py
init.py
from flask_api import FlaskAPI
from flask_sqlalchemy import SQLAlchemy
from flask import Flask, jsonify, request
# local import
from instance.config import app_config
# initialize sql-alchemy
db = SQLAlchemy()
def create_app(config_name):
app = FlaskAPI(__name__, instance_relative_config=True)
app.config.from_object(app_config["development"])
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
#app.route("/", methods=['GET'])
def test():
return jsonify({'message':'It works!'})
return app
test_mealapp.py
import unittest
import os
import json
from app import create_app
class FlaskTestCase(unittest.TestCase):
def test_index(self):
"""Define test variables and initialize app."""
self.app = create_app(config_name="testing")
self.client = app.client.test_client
response = self.client("/")
# self.assertEqual(response[message],"It works!")
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
Any tips on how to fix my test_mealapp.py?

This would work:
class FlaskTestCase(unittest.TestCase):
def test_index(self):
self.app = create_app(config_name="testing")
with self.app.test_client() as client:
response = client.get("/")
responseJson = json.loads(response.data)
self.assertEqual(responseJson['message'], "It works!")
self.assertEqual(response.status_code, 200)
Try to always use the client in a with: block and make sure to use the request method as the attribute to client (get in this case)

Related

Tests keep using "production" database even after I change sqlalchemy_database_uri in pytest fixture

I have flask application that I am using to get familiar with the flask-sqlalchemy lib and testing using Pytest with fixtures.
I am trying to overwrite the sqlalchemy_database_uri in the app configuration in my test fixtures. But the problem is that when I run them, my tests seem to be working with the "production" database rather than with an ephemeral one. The test record I created for test via fixtures are all in the database that I create in the app initialization.
When I run the test in the example below using pytest from the root folder in that structure. The tests are collected ok, run and pass as expected. But after running the tests a new database called hello.db has been created in the instance folder. What I am trying to do is that the tests use a sqlite database in memory that disapears after the tests run.
How do I go about writing/configuring my tests so that I use an ephemeral sqlite database in memory that is only used for those tests?
# Folder structure
.
├── mini_app
│   ├── __init__.py
│   ├── app.py
│   ├── config.py
│   └── models.py
└── tests
├── __init__.py
└── test_all.py
## app.py
from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from mini_app import config
db = SQLAlchemy()
def create_app(cfg= None):
if cfg is None:
cfg = config.Config()
app = Flask(__name__)
app.config.from_object(cfg)
# Init_apps
db.init_app(app)
#app.route("/square")
def square():
"""A view which uses no templates and no database."""
number = int(request.args.get("number", 0))
return str(number ** 2)
return app
## config.py
class Config:
SQLALCHEMY_DATABASE_URI = "sqlite:///hello.db"
## models.py
from mini_app.app import db
class Author(db.Model):
__tablename__ = "authors"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String)
## test_all.py
import pytest
import mini_app.app
import mini_app.models
#pytest.fixture
def client():
# Prepare before your test
app = mini_app.app.create_app()
app.config["TESTING"] = True
app.testing = True
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://"
with app.test_client() as client:
with app.app_context():
mini_app.app.db.create_all()
author1 = mini_app.models.Author(id=1, name="foo")
mini_app.app.db.session.add(author1)
mini_app.app.db.session.commit()
# Give control to the test
yield client
# Cleanup after the test run.
# ... nothing here, for this simple example
def test_square(client):
rv = client.get("/square?number=8")
assert b"64" == rv.data

Adding dash to flask app where dash need to access db and user session_id

I have a flask app with the following structure:
/test
├── /application
│ ├── __init__.py
│ ├── routes.py
│ ├── /static
│ ├── /templates
│ └── /dashboard
│ └── __init__.py
├── db.py
├── config.py
├── requirements.txt
├── helpers.py
└── wsgi.py
I am trying to implement a dash dashboard by intitating it through calling a function in application.init.py
where the function is define in dashboard.init.py
my application.init.py
def init_app():
"""Construct core Flask application."""
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.Config')
# Ensure responses aren't cached
#app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
# Custom filter
app.jinja_env.filters["usd"] = usd
Session(app)
assets = Environment()
assets.init_app(app)
with app.app_context():
# Import parts of our core Flask app
from . import routes
from .assets import compile_static_assets
# Import Dash application
from .dashboard import init_dashboard
app = init_dashboard(app)
# Compile static assets
compile_static_assets(assets)
return app
in dashboard.init.py file the function init_dashboard need to access the database and the user id, because the dashboard layout need to use values from the database so that it will show the specific dashboard for the user, but of course this does not work as it return the error "Working outside of request context".
If I will try to create the dashboard in routes for example:
#app.route("/dashapp/")
#login_required
def redirect_to_dashapp():
dash_app = dash.Dash(
server=app,
routes_pathname_prefix="/dashapp/")
"""Create a Plotly Dash dashboard."""
stocks = db.session.query(Records.symbol, Records.number_of_shares, Records.purchase_p, Records.execution_time).filter_by(user_id=session["user_id"]).all()
.....
it will return the error "A setup function was called after the first request was handled. "
As the dash layout need values from the database I can't initiate it in init_dashboard() without accessing the db, and I can't initiate in routes either.
Does anyone has a suggestion on how to properly do it?

How to defined a database connecting Flask python file and then import it?

1.I was trying to use Pymongo to connect to my MongoDB atlas database. I wrote this file into the connect.py file. Here is the tree folder structure. The connect.py contains the URL information to connect the database.
└── uploading
├── __pycache__
│   └── upload.cpython-38.pyc
└── upload.py
├── Database
│   ├── __pycache__
│   │   └── connect.cpython-38.pyc
│   └── connect.py
├── app.py
2.Here is code for connect.py
import pymongo
client = pymongo.MongoClient("URL",ssl=True, ssl_cert_reqs='CERT_NONE')
db = client.datasets
Here is the code for uplod.py
from flask import Blueprint, current_app
from Database.connect import db
sample = Blueprint('sample', __name__)
#sample.route('/')
def index():
x = current_app.config['UPLOAD_PATH']
return str(db)
Here is the code for app.py:
app = Flask(__name__)
app.secret_key = b'pj&\xe9\xd7\xd7\xabc\xe6KX\xbe\x9f<\x9f\x87'
app.config['UPLOAD_PATH'] = 'public' # to create a folder which is used to save the uploaded file
CORS(app)
app.register_blueprint(sample)
'''
Datasets and model upload
'''
#app.route('/connect-upload', methods=["POST"])
#cross_origin()
def connect_upload():
index=0
# get username
return "result"
When I tried to use : from Database.connect import db to import database in the upload.py, it showed error message :ImportError: cannot import name 'db' from 'Database.connect'. How can I solve this problem?
You are not referencing your module correctly. Your module should be the filename. You should use from connect import db.

Flask alchemy doesn't create database table for the model class

I created a simple boilerplate flask application with one class in the model. My problem is that my app doesn't create the table in the mysql database after the app first run. Ideally, table should be created only if it doesn't exist (so I can leave the create_all instruction in the code)
project tree is:
.
├── application.py
├── module
│   ├── __init__.py
│   ├── __pycache__
│   │   └── __init__.cpython-36.pyc
│   └── models.py
├── requirements.txt
├── static
└── templates
That's the content of application.py file
from flask import Flask
from module import db
app = Flask(__name__)
app.config['DEBUG'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://oskar:secret#ipaddress/analytics'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
#app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
# with app.app_context():
db.init_app(app)
app.app_context().push()
# create tables only once
db.create_all(app=app)
db.session.commit()
app.run()
Content of module/__init__.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Content of module/models.py
from module import db
class PostalCodeCities(db.Model):
postal_code = db.Column(db.String(6), nullable=False) # kod pocztowy
city = db.Column(db.String(126), nullable=False) # miejscowosc
street = db.Column(db.String(126))
building = db.Column(db.String(32))
municipality = db.Column(db.String(126)) # gmina
county = db.Column(db.String(126)) # powiat
voivodeship = db.Column(db.String(126)) # wojewodztwo
def __repr__(self):
return '<PostalEntry %r>' % self.postal_code
What I'm doing wrong?
Thanks!
I already found the solution. I had to move everything from __init__.py to models.py and in applications.py import db from module.models

Using Flask Restful as a Blueprint in Large Application

I am trying to use Flask restful as a Blueprint in a pattern that works for other blueprints. I keep getting the following error message
I get the following error message
AttributeError: 'Blueprint' object has no attribute 'add_resource'
My project setup is as follows:
Folder structure
├── app
│   ├── __init__.py
│   ├── api
│   │   ├── __init__.py
│   │   └── routes.py
│   ├── main
│   │   ├── __init__.py
│   │   ├── forms.py
│   │   └── views.py
│   └── templates
│   ├── base.html
│   └── home.html
├── config.py
├── manage.py
└── requirements.txt
__init__.py
from flask import Flask
from flask_restful import Api
from flask_bootstrap import Bootstrap
from config import config
bootstrap = Bootstrap()
api = Api()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
api.init_app(app)
from .main import main as main_blueprint
from .api import api as api_blueprint
app.register_blueprint(main_blueprint)
app.register_blueprint(api_blueprint)
return app
api/__init__.py
from flask import Blueprint
api = Blueprint('api', __name__)
from . import routes
api/routes.py
from flask_restful import Resource
from . import api
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
api.add_resource(TodoItem, '/todos/<int:id>')
What am I doing wrong??
If you follow the instructions from https://flask-restful.readthedocs.io/en/0.3.5/intermediate-usage.html
The key points here are to create a Flask Blueprint instance & pass it to a new instance of flask-restfuls's Api class.
Lastly, make sure to register the flask-restful api blueprint within your create_app function: app.register_blueprint(api_bp)
from flask import Flask, Blueprint
from flask_restful import Api
from flask_bootstrap import Bootstrap
from config import config
bootstrap = Bootstrap()
api_bp = Blueprint('api', __name__)
api = Api(api_bp)
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
from .users import main as users_blueprint
from .blogs import main as blogs_blueprint
# blueprints for blogs & users
app.register_blueprint(users_blueprint)
app.register_blueprint(blogs_blueprint)
app.register_blueprint(api_bp)
return app
Also note, you don't need to register api.init_app(app) anymore.
You're running in to trouble because of how you've named your blueprint api, whilst also using the api object from flask_restful. In your routes.py you're explicitly importing api from api/__init__.py, and this is a Blueprint object. You can't call add_resource to a Blueprint object, only to an Api object from flask_restful.
If you change your import to:
from .. import api
you'll be importing the correct object. I'd still recommend changing your blueprint name anyway to avoid this sort of confusion.
If you want to have submodules (like your /api) based on resources...
Eg: folder structure
├── app
│ ├── __init__.py
│ ├── foo
│ │ ├── __init__.py
│ │ └── routes.py
│ ├── boo
│ │ ├── __init__.py
│ │ └── routes.py
├── config.py
├── manage.py
... and register their blueprints with url_prefix to not repeat the common part in each added resource. Create new Api instance in each module and pass to it a blueprint.
foo/__init__.py
from flask import Blueprint
from flask_restful import Api
foo_bp = Blueprint('foo', __name__, url_prefix='/foo')
foo_api = Api(foo_bp)
from . import routes
in routes import foo_api and add resources to it
foo/routes.py
from flask_restful import Resource
from . import foo_api
class TodoItem(Resource):
def get(self, id):
return {'task': 'Say "Hello, World!"'}
foo_api.add_resource(TodoItem, '/todos/<int:id>')
Then in main application __init__.py just import modules blueprints and register it. You dont even need to add a "main" application blueprint. If you would import the api from main application __init__ then you can't register each blueprint with it's own params like url_prefix.
__init__.py
from flask import Flask
from config import config
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
from .foo import foo_bp
from .boo import boo_bp
app.register_blueprint(foo_bp)
app.register_blueprint(boo_bp)
return app
You can set the url_prefix on register blueprint (it has priority) or when you create it. To check routes you can print the app.url_map