-1

I want to write unit test for some of the function of my application and for that I need to mock some SQLAlchemy call to my db. The problem is everytime I tried it gives me an error : "RuntimeError: No application found."

This is the function I want to unit test :

def update_user(user_uid, new_info):
    user = db.session.query(User).filter_by(uid=user_uid).first()

    # check if values are the same before changing
    # ensure unique username and email for all users
    if user.username != new_info["username"]:
        if db.session.query(User).filter_by(username=new_info["username"]).first() is not None:
            return {"success": "False", "code": "400", "result": "Username already taken"}
        else:
            user.username = new_info["username"]

    if user.email != new_info["email"]:
        if db.session.query(User).filter_by(email=new_info["email"]).first() is not None:
            return {"success": "False", "code": "400", "result": "Email already taken"}
        else:
            user.email = new_info["email"]

    if user.subscription_uid != new_info["subscription_uid"]:
        user.subscription_uid = new_info["subscription_uid"]

    # password only has length if being changed
    if len(new_info["password"]):
        hashed = bcrypt.hashpw(new_info["password"].encode("utf-8"), bcrypt.gensalt())
        user.password = hashed.decode("utf-8")

    db.session.commit()
    return {"success": "True", "code": "200", "result": "User updated successfully"}

I want to mock all the

db.session

I tried doing this :

class TestUser(unittest.TestCase):
    def test_update_user(self):
        user_db = {"username": "user", "email": "user@test.com", "subscription_uid": "1", "password": ""}
        info_user_same_username = {"username": "user", "email": "new_user@test.com", "subscription_uid": "1", "password": ""}
        info_user_same_email = {"username": "new_user", "email": "user@test.com", "subscription_uid": "1", "password": ""}
        info_new_user = {"username": "new_user", "email": "new_user@test.com", "subscription_uid": "2", "password": "new_password"}

        with mock.patch('flask_sqlalchemy._QueryProperty.__get__') as mock_user:
            mock_user.return_value = user_db

            response_correct = {"success": "True", "code": "200", "result": "User updated successfully"}
            response_same_username = {"success": "False", "code": "400", "result": "Email already taken"}
            response_same_email = {"success": "False", "code": "400", "result": "Username already taken"}

            response = update_user(1, info_new_user)
            response_username = update_user(1, info_user_same_username)
            response_email = update_user(1, info_user_same_email)

            self.assertEqual(response, response_correct)
            self.assertEqual(response_username, response_same_username)
            self.assertEqual(response_email, response_same_email)

But I got this error :

Traceback (most recent call last):
  File "C:\Users\gusta\OneDrive\Documents\Pomelo\backend\pomelo_backend\tests\test_User.py", line 23, in test_update_user
    response = update_user(1, info_new_user)
  File "C:\Users\gusta\OneDrive\Documents\Pomelo\backend\pomelo_backend\user.py", line 8, in update_user
    user = db.session.query(User).filter_by(uid=user_uid).first()
  File "<string>", line 2, in query
  File "C:\Users\gusta\OneDrive\Documents\Python\backend\lib\site-packages\sqlalchemy\orm\scoping.py", line 105, in _proxied
    return self.registry()
  File "C:\Users\gusta\OneDrive\Documents\Python\backend\lib\site-packages\sqlalchemy\util\_collections.py", line 1010, in __call__
    return self.registry.setdefault(key, self.createfunc())
  File "C:\Users\gusta\OneDrive\Documents\Python\backend\lib\site-packages\sqlalchemy\orm\session.py", line 4058, in __call__
    return self.class_(**local_kw)
  File "C:\Users\gusta\OneDrive\Documents\Python\backend\lib\site-packages\flask_sqlalchemy\__init__.py", line 174, in __init__
    self.app = app = db.get_app()
  File "C:\Users\gusta\OneDrive\Documents\Python\backend\lib\site-packages\flask_sqlalchemy\__init__.py", line 1043, in get_app
    'No application found. Either work inside a view function or push'
RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.

I tried some other methods: - using alchemy-mock - @patch('flask_sqlalchemy._QueryProperty.get')

But always the same error message.

snakecharmerb
  • 47,570
  • 11
  • 100
  • 153
  • Have you looked at the information that the link in the error message points to? `RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.` – snakecharmerb Apr 29 '21 at 08:52

1 Answers1

0

You're trying to use SQLAlchemy outside of an application context which isn't allowed.

To push an application context in your tests, you have to import your app:

from module import app

In flask, you can set TESTING to True in your app config:

app.config['TESTING'] = True

Then inside of your test, you have to push the application context:

def test_something(self):
    with app.test_client() as client:
        # do something

This is especially useful when testing routes, because you can send a request to your app and test the response i.e:

def test_something(self):
    with app.test_client() as client:
        res = client.get('/users')
        res_html = res.get_data(as_text=True)
        self.assertEqual(res.status_code, 200)
        self.assertIn('<div id="target-div">', res_html)
Leshawn Rice
  • 617
  • 4
  • 13