0

I am writing an API in a flask and I use the application factory. This is how my __init__.py looks.

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_restful import Api

db = SQLAlchemy()
api = Api()   

def create_app():
    app = Flask(__name__, instance_relative_config=False)
    app.config.from_object("config.Config")

    db.init_app(app)
    api.init_app(app)

    with app.app_context():
        db.create_all()
        return app

In wsgi.py (which in entry point to start) I have my endpoints.

# some more imports
from application import create_app 
app = create_app()

# some more endpoints
api.add_resource(Products, "/products") # GET
                    
if __name__ == "__main__":
    # some more code here..
    app.run(debug=True)

Now I want to write some unittest, but the problem is I constantly get 404 not found on the enpoinds, even thought in postman it work fine.

this is my test.

from unittest import TestCase
from application import create_app
from application import db

app = create_app()


class ProductTest(TestCase):

    def setUp(self) -> None:
        """ Prepare new database and test client. """
        app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///"
        with app.app_context():
            db.init_app(app)
            db.create_all()
        self.app = app.test_client
        self.app_context = app.app_context

    def test_get_products(self):
        with self.app() as client:
            with self.app_context():
                res = client.get("/products")
                self.assertEqual(res.status_code, 200)  # it fails - it returns 404 everytime

I suppose there is some problem with the create_app thing. I don't know exactly how to use it in test. When I write the same API but without using the application factory (and thus without create_app), this test passes.

Can anyone explain me what I am doing wrong and how to use create_app from application factory with unit testing endpoints?

Sergey Shubin
  • 3,040
  • 4
  • 24
  • 36
experimental
  • 129
  • 1
  • 10
  • Why do you add the resources in the `wsgi.py` module? You can do it in the `__init__.py`. Your test module doesn't import `wsgi.py` so the code `api.add_resource(Products, "/products")` is not executed. – Sergey Shubin Aug 27 '20 at 13:34
  • oh man, you are genius, if this is going to work, you will save me such a headache. thank you for the answer. i will try – experimental Aug 27 '20 at 20:49
  • hmm.. but the problem now is that I have some circular import issues.. because in the __init__ I have to import the model and in the model I am importing db, and create_app... so I am stuck again. :( any idea how to fix it? – experimental Aug 28 '20 at 00:24
  • You can move `flask_sqlalchemy` initialization to a separate module and then import it to your models and `__init__` module as described in this [answer](https://stackoverflow.com/a/23400668/6682517). – Sergey Shubin Aug 28 '20 at 06:05
  • yeah that is what i did but still there is problem with the create_app function which I am importing to model, and the models are imported in __init__ - this bit I dont know how to solve – experimental Aug 28 '20 at 08:07
  • But why do you need to import application factory to the model? It is required only when you are going to run it. If you need something from the `Flask` object like its config for example you can use [current_app](https://flask.palletsprojects.com/en/1.1.x/api/#flask.current_app) global variable to get it. Like other `Flask` global variables it works only while application context is available but is enough for most problems. – Sergey Shubin Aug 28 '20 at 09:42
  • that is the thing. I was also thinking about the same but I need it there otherwise it tells me I work outside of application context. I have no clue why. I tried import current_app but it just did not work. It still kept telling I was outside context. When I imported create_app it worked. This is really tricky part and I would really like to understand what the problem is there.. – experimental Aug 28 '20 at 10:08
  • It may happen if some database operations are executed before the application launches. For example if they are executed on import level in some of your files. Anyway if you can't find it you can create a new SO question for this application context problem because it will require posting more code outside of the scope of the current question. – Sergey Shubin Aug 28 '20 at 11:15
  • ok. i made it here: https://stackoverflow.com/questions/63634038/how-to-avoid-importing-application-factory-into-module-that-needs-application-co your insight is much appreciated! – experimental Aug 28 '20 at 12:46

0 Answers0