2

I'm currently writing a simple flask application and want to test that my configuration options are working.

Here's my config.py:

import logging
import logging.handlers
import os


class BaseConfig(object):
    DEBUG = False
    TESTING = False
    ...


class DevelopmentConfig(BaseConfig):
    DEBUG = True
    TESTING = True
    ...


class TestingConfig(BaseConfig):
    DEBUG = False
    TESTING = True
    ...

config = {
    'development': 'app.config.DevelopmentConfig',
    'testing': 'app.config.TestingConfig',
    'default': 'app.config.BaseConfig'
}


def configure_app(app):
    config_name = os.environ.get('FLASK_CONFIGURATION', 'default')
    app.config.from_object(config[config_name])
    app.config.from_pyfile('config.py', silent=True)
    apikey = os.environ.get('TOKEN', None)
    if apikey:
        app.config['APIKEY'] = apikey

I call configure_app in my __init__.py right after I create the Flack object.

app = Flask(__name__)
configure_app(app)

config.py:

APIKEY = 'filesecret'
HOOKS = {'testpush': 'scripts/test.sh'}

What I want to do is be able to unittest using py.test the various configuration options. My current attempt is to try and use mock_open, but the configuration keep reading what's in the file instead of skipping it.

class TestConfig:

    def setup(self):
        self.app = app.app
        self.app.config['TESTING'] = True

    def test_default(self, mocker):
        m = mocker.mock_open(read_data='')
        configure_app(self.app)
        assert self.app.config['APIKEY'] == "secret"

results of test:

    def test_default(self, mocker):
        m = mocker.mock_open(read_data='')
        configure_app(self.app)
>       assert self.app.config['APIKEY'] == "secret"
E       assert 'filesecret' == 'secret'

I'm not sure how to do this when I don't know the internals of flask. Is there a way to fake/mock the file? I want to be able to write the various test cases of the configuration file being present, not present, and the environment variable being set to make sure priority is maintained.

1 Answers1

0

So I was going about this all wrong. I looked at Flask's source code and saw how they were testing their configuration functions, and they simply instantiated a new Flask object with their own environment variables.

Flask project test_config.py

Using the context manager found on this stackoverflow question (currently the bottom answer with contextlib) to set my environment variables I got this all working great.

Final test:

@pytest.mark.parametrize(
    'envtoken, flask_conf, test_path, apikey, debug, testing', [
        ('', 'default', 'missing', 'secret', False, False),
        ('', 'development', 'missing', 'secret', True, True),
        ('', 'testing', 'missing', 'secret', False, True),
        ('', 'default', '../tests/data', 'filesecret', False, False),
        ('envsecret', 'default', '../tests/data/', 'envsecret', False, False)])
def test_config_app(envtoken, flask_conf, test_path, apikey, debug, testing):
    with set_env(DOCKERHOOK_TOKEN=envtoken, FLASK_CONFIGURATION=flask_conf):
        # app = Flask(__name__)
        base_path = get_app_base_path()
        instance_path = os.path.join(base_path, test_path)

        app = Flask(__name__,
                    instance_path=instance_path,
                    instance_relative_config=True)

        configure_app(app)

        assert app.config['APIKEY'] == apikey
        assert app.config['DEBUG'] == debug
        assert app.config['TESTING'] == testing
Community
  • 1
  • 1