简体   繁体   English

使用 pytest 进行 Flask 测试,ENV 是否设置为生产?

[英]Flask testing with pytest, ENV is set to production?

I have built a flask app and i would like to create a test suite.我已经构建了一个烧瓶应用程序,我想创建一个测试套件。 Reading around it looks like pytest is the way to go;阅读它看起来像 pytest 是要走的路; however, I am finding it very difficult to understand how to get going, I have looked at https://flask.palletsprojects.com/en/2.0.x/testing/ but am struggling to relate it to my app.但是,我发现很难理解如何开始,我查看了https://flask.palletsprojects.com/en/2.0.x/testing/但我很难将它与我的应用程序联系起来。

my project has a run.py at its base:我的项目在其基础上有一个 run.py:

from wahoo_connect import init_app, db
from flask_migrate import Migrate

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

this is run using flask run and the .flaskenv sets the mode这是使用 flask run 运行的,.flaskenv 设置模式

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

I have an application factory set up:我设置了一个应用程序工厂:

"""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

Everything works and I can run the app on a production server.一切正常,我可以在生产服务器上运行该应用程序。 I am trying to get started with pytest and have set up conftest.py:我正在尝试开始使用 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

this always runs the app in production mode, how do I get it to run in testing mode so that it uses the correct config from config.py这总是在生产模式下运行应用程序,我如何让它在测试模式下运行,以便它使用 config.py 中的正确配置

"""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

If there is a good tutorial that I have missed I'd be pleased to hear.如果有我错过的好教程,我会很高兴听到。

Thank you in advance.先感谢您。

Martyn马丁

What is Dotenv什么是 Dotenv

Use Dotenv package使用Dotenv

#test.py
from os import environ

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

How to use it in youre case如何在您的情况下使用它

Option 1选项1

You can use this to store an Boolean in .env file and read it to define wich mode you are running.您可以使用它在 .env 文件中存储一个布尔值并读取它来定义您正在运行的模式。 be careful as env variables get read as string.当 env 变量被读取为字符串时要小心。 if you wanna use boolean you need to parse them from the string.如果你想使用布尔值,你需要从字符串中解析它们。

Option 2选项 2

An other option is to store in env file which config you wanna use and make an if else tree in python script:另一种选择是将您要使用的配置存储在 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")

Why use Dotenv为什么要使用 Dotenv

The advantage of using environment variables is that you can ignore them in git and every time the server is seetup in linux or docker all settings can be managed from one file.使用环境变量的好处是你可以在 git 中忽略它们,每次在 linux 或 docker 中设置服务器时,所有设置都可以从一个文件中管理。 also does the standart server admin know bash script and env files but not necesseraly python.标准服务器管理员也知道 bash 脚本和 env 文件,但不一定知道 python。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM