7

I want to unit test following function:

from flask import current_app

def fuu():
    current_app.logger.info('hello world')
    any = current_app.config['any']

Without any special context handling I receive following error message:

E           This typically means that you attempted to use functionality that needed
E           to interface with the current application object in some way. To solve
E           this, set up an application context with app.app_context().  See the
E           documentation for more information.

After reading about Flask context, I came up with a working solution:

@classmethod
def setUpClass(cls):
    app = app_factory.create_app()
    ctx = app.app_context()
    ctx.push()
    cls.app = app

But the point is that I do not want to deal with any flask contexts in UNIT tests. I want to have a plain unit test, in which all collaborators can be mocked, so that the system under test just deals with mocked instance, in this case for current_app as well. Having flask context is pretty fine for integration testing, but not for unit testing.

I am searching for something similar like this:

 @patch('flask.current_app')

Is there any way to achieve this?

EDIT #1

@Gabriel C

service.py

from flask import current_app

def fuu():
    current_app.logger.info('hello world')

service_test.py

import unittest
from unittest.mock import patch

class TestService(unittest.TestCase):

@patch('flask.current_app')
def test_generate_image_happy_path(self, mock):
    from service import fuu
    fuu()
    assert 1 == 1

This fails for the same exact reason:

E           RuntimeError: Working outside of application context.
Christopher Will
  • 2,991
  • 3
  • 29
  • 46

2 Answers2

7

Answering for anyone that runs into the same issue. What you can do is create a dummy Flask app and use its context in your test. No need to patch anything.

import unittest
from service import fuu


class TestService(unittest.TestCase):
    app = Flask('test')

    def test_generate_image_happy_path(self):
        with app.app_context():
            fuu()
            assert 1 == 1

Of course if you want to have access to your Flask config, you'd have to pass that in to this dummy app.

Darius Mandres
  • 778
  • 1
  • 13
  • 31
4

Edit: Correct patch when using from flask import current_app

service.py

from flask import current_app

def fuu():
    current_app.logger.info('hello world')

service_test.py

import unittest
from unittest.mock import patch


class TestService(unittest.TestCase):

    @patch('service.current_app')
    def test_generate_image_happy_path(self, mock):
        from service import fuu
        fuu()
        assert 1 == 1
Gabriel Cappelli
  • 3,632
  • 1
  • 17
  • 31
  • 1
    No success either, please see the code in my edited question. – Christopher Will Sep 16 '19 at 07:00
  • 2
    I've updated my answer. Since you're using `from python import current_app` we need to patch `service.current_app` (Full explanation here: https://docs.python.org/3/library/unittest.mock.html#where-to-patch). – Gabriel Cappelli Sep 16 '19 at 20:00
  • It should work. But honestly, it's best to use the test client. https://flask.palletsprojects.com/en/1.1.x/testing/#keeping-the-context-around – Gabriel Cappelli Jun 12 '20 at 14:55
  • 3
    @GabrielCappelli using the test client is good for integration tests, i.e. testing your routes and db. Here however, he is talking about unit tests, which is testing pieces of code individually – Darius Mandres Sep 15 '20 at 21:24