使用pytest进行烧瓶测试,ENV设置为生产?

Flask testing with pytest, ENV is set to production?

我已经构建了一个 Flask 应用程序,我想创建一个测试套件。阅读它看起来像 pytest 是要走的路;但是,我发现很难理解如何开始,我看过 https://flask.palletsprojects.com/en/2.0.x/testing/ 但很难将它与我的应用程序联系起来。

我的项目在其基础上有一个 run.py:

from wahoo_connect import init_app, db
from flask_migrate import Migrate

#run the app
app = init_app()
migrate = Migrate(app, db)

这是 运行 使用 flask 运行 并且 .flaskenv 设置模式

FLASK_APP=run.py
#FLASK_ENV=production
FLASK_ENV=development

我设置了一个应用程序工厂:

"""Main entry point into App"""
#import libraries
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_mail import Mail
#from flask_caching import Cache
from flask_session import Session
from os import path, mkdir
import logging
from logging.handlers import SMTPHandler, RotatingFileHandler

"""Flask Global Variables"""
#database connection
db = SQLAlchemy()
migrate = Migrate()

#login manager
login = LoginManager()
login.login_view = 'auth_bp.login'
login.login_message = 'Please log in to access this page.'
login.login_message_category = "info"

#email
mail = Mail()

#cache
#cache = Cache()

#session
sess = Session()

#initialise app
def init_app():
    """Initialize the core application."""
    app = Flask(__name__)
    print(app.config['ENV'])
    if app.config['ENV'] == 'production':
        app.config.from_object('wahoo_connect.config.ProductionConfig')
    elif app.config['ENV'] == 'development':
        app.config.from_object('wahoo_connect.config.DevelopmentConfig')
    elif app.config['ENV'] == 'testing':
        app.config.from_object('wahoo_connect.config.TestingConfig')

    # Initialize Plugins
    db.init_app(app)
    migrate.init_app(app, db)
    login.init_app(app)
    mail.init_app(app)
#    cache.init_app(app)
    sess.init_app(app)

    with app.app_context():
        # Import and Register Blueprints
        from wahoo_connect.errors.views import errors_bp
        from wahoo_connect.auth.views import auth_bp
        from wahoo_connect.profile.views import profile_bp
        from wahoo_connect.wahoo.views import wahoo_bp
        from wahoo_connect.home.views import home_bp
        app.register_blueprint(errors_bp)
        app.register_blueprint(auth_bp, url_prefix='/auth')
        app.register_blueprint(profile_bp)
        app.register_blueprint(wahoo_bp, url_prefix='/wahoo')
        app.register_blueprint(home_bp)

        if not app.debug:
            #log to email
            if app.config['MAIL_SERVER']:
                auth = None
            if app.config['MAIL_USERNAME'] or app.config['MAIL_PASSWORD']:
                auth = (app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD'])
            secure = None
            if app.config['MAIL_USE_TLS']:
                secure = ()
            mail_handler = SMTPHandler(
                mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']),
                fromaddr=app.config['MAIL_USERNAME'],
                toaddrs=app.config['ADMINS'],
                subject='Error in Wahoo-Connect',
                credentials=auth, secure=secure)
            mail_handler.setLevel(logging.ERROR)
            app.logger.addHandler(mail_handler)

            #log to file - heroku
            if app.config['LOG_TO_STDOUT']:
                stream_handler = logging.StreamHandler()
                stream_handler.setLevel(logging.INFO)
                app.logger.addHandler(stream_handler)
            else:
                logdir = path.dirname(app.instance_path) + '/logs'
                if not path.exists(logdir):
                    mkdir(logdir)
                file_handler = RotatingFileHandler(logdir + '/wahoo-connect.log', 
                    maxBytes=10240, backupCount=10)
                file_handler.setFormatter(logging.Formatter(
                    '%(asctime)s %(levelname)s: %(message)s '
                    '[in %(pathname)s:%(lineno)d]'))
                file_handler.setLevel(logging.INFO)
                app.logger.addHandler(file_handler)

            app.logger.setLevel(logging.INFO)
            app.logger.info('Wahoo-Connect Startup')

        return app

from wahoo_connect import models

一切正常,我可以 运行 生产服务器上的应用程序。我正在尝试开始使用 pytest 并设置 conftest.py:

import pytest
from wahoo_connect import init_app
from wahoo_connect.models import User

@pytest.fixture(scope="session")
def app():
    app = init_app()
    return app

这总是 运行 生产模式下的应用程序,我如何在测试模式下将其设置为 运行 以便它使用来自 config.py[=16= 的正确配置]

"""Flask configuration."""
from os import environ, path
from dotenv import load_dotenv
from datetime import timedelta

#basedir = path.abspath(path.dirname(__file__))
basedir = path.dirname(path.dirname(path.abspath(__file__)))
load_dotenv(path.join(basedir, '.env'))

class Config(object):
    """Base config."""
    DEBUG = False
    TESTING = False
    SECRET_KEY = environ.get('SECRET_KEY') or 'topsecretkey'
    STATIC_FOLDER = 'static'
    TEMPLATES_FOLDER = 'templates'
    SESSION_COOKIE_SECURE = True

    #Database
    SQLALCHEMY_DATABASE_URI = environ.get('DATABASE_URL') or \
        'sqlite:///' + path.join(basedir, 'app.db')
    #fix for heroku postgres db
    if SQLALCHEMY_DATABASE_URI.startswith("postgres://"):
        SQLALCHEMY_DATABASE_URI = SQLALCHEMY_DATABASE_URI.replace("postgres://", "postgresql://", 1)
    SQLALCHEMY_TRACK_MODIFICATIONS = False

    #Wahoo
    WAHOO_CLIENT_ID=environ.get('WAHOO_CLIENT_ID')
    WAHOO_CLIENT_SECRET=environ.get('WAHOO_CLIENT_SECRET')
    WAHOO_CLIENT_REDIRECT=environ.get('WAHOO_CLIENT_REDIRECT')

    #Email
    MAIL_SERVER = environ.get('MAIL_SMTP_SERVER')
    MAIL_PORT = int(environ.get('MAIL_SMTP_PORT') or 25)
    MAIL_USERNAME = environ.get('MAIL_SMTP_LOGIN')
    MAIL_PASSWORD = environ.get('MAIL_SMTP_PASSWORD')
    MAIL_USE_TLS = environ.get('MAIL_USE_TLS') is not None
    ADMINS = ['martyndwheeler@gmail.com']

    #Logging
    LOG_TO_STDOUT = environ.get('LOG_TO_STDOUT') or None

    # Flask-Caching related configs
    CACHE_TYPE = 'FileSystemCache'
    CACHE_DIR = environ.get('CACHE_DIR') or None
    CACHE_DEFAULT_TIMEOUT = 300
    CACHE_THRESHOLD = 100

    # Flask-Session related configs
    SESSION_PERMANENT = False
    PERMANENT_SESSION_LIFETIME = timedelta(minutes=30)
    SESSION_USE_SIGNER = True
    SESSION_TYPE = "filesystem"
    SESSION_FILE_DIR = environ.get('SESSION_FILE_DIR')
    SESSION_FILE_THRESHOLD = 100

class ProductionConfig(Config):
    pass

class DevelopmentConfig(Config):
    DEBUG = True
    SESSION_COOKIE_SECURE = False

class TestingConfig(Config):
    TESTING = True
    SESSION_COOKIE_SECURE = False

如果有我错过的好教程,我会很高兴听到。

什么是Dotenv

使用Dotenv

#test.py
from os import environ

print(environ.get("ENV_VAR")) # Output : test
#.env
ENV_VAR=test

在你的情况下如何使用它

选项 1

您可以使用它在 .env 文件中存储一个布尔值并读取它来定义您所处的模式 运行。当环境变量被读取为字符串时要小心。如果你想使用布尔值,你需要从字符串中解析它们。

选项 2

另一种选择是将您要使用的配置存储在 env 文件中,并在 python 脚本中创建一个 if else 树:

if os.environ.get("CONFIG") == "1":
    app.config.from_object("config.conf1")
elif os.environ.get("CONFIG") == "2":
    app.config.from_object("config.conf2")
else:
    app.config.from_object("config.default")

为什么要用Dotenv

使用环境变量的优点是您可以在 git 中忽略它们,并且每次在 linux 或 docker 中设置服务器时,所有设置都可以从一个文件中管理.标准服务器管理员也知道 bash 脚本和 env 文件但不一定 python.