简体   繁体   English

FastAPI 测试 否 ORM 数据库

[英]FastAPI testing No ORM Databases

I am a None ORM user, I prefer to use plain text queries, I took that course on free code camp on FastAPI but almost the whole course revolves around ORMs so I struggle to implement a number of concepts found in that course.我是无 ORM 用户,我更喜欢使用纯文本查询,我在 FastAPI 上的免费代码营上学习了该课程,但几乎整个课程都围绕 ORM,所以我很难实现该课程中的一些概念。

My main struggle is when I write tests for my endpoints I need to use a test database rather than my development database, I am using testing.postgres to create the testing database and this is the code I am using:我的主要困难是当我为端点编写测试时,我需要使用测试数据库而不是我的开发数据库,我正在使用testing.postgres创建测试数据库,这是我正在使用的代码:

client = TestClient(app)

class TestUser:
    def setup_method(self, method):
        self.postgres = testing.postgresql.Postgresql(cache_initialized_db=True)
        self.db = psycopg2.connect(**self.postgres.dsn())

    def teardown_method(self, method):
        self.db.close()

    def test_get_users(self):
        res = client.get("/users")
        assert res.status_code == 200
        assert res.headers["content-type"] == "application/json"

my question is how to make my tests and cruds send queries to the test database, not the development database.我的问题是如何让我的测试和 cruds 将查询发送到测试数据库,而不是开发数据库。

where is the link that I should add here?我应该在这里添加的链接在哪里?

Edit: this is the code I use for connection with database, I am not using a dependency for it:编辑:这是我用于连接数据库的代码,我没有使用它的依赖项:

while True:
    try:
        conn = psycopg2.connect(
            database=settings.database,
            user=settings.user,
            port=settings.port,
            password=settings.password,
            cursor_factory=RealDictCursor,
        )
        cr = conn.cursor()
        console.print(
            "[green bold]SUCCESS[/]:    Connection To Database Established successfuly"
        )
        break
    except psycopg2.OperationalError:
        console.print(
            "[red bold]FAILED[/]:    Connection To Database Failed , Trying Again"
        )
        time.sleep(2)

Edit2: this is the settings segment: Edit2:这是设置部分:

load_dotenv()


class Settings(BaseSettings):
    database: str
    user: str
    port: int
    password: str
    expiray: int
    algorithm: str
    secret_key: str


settings = Settings()

If you wanna use the test database rather than the development database you should create the testing database and let the backend application be able to find the testing database and use it.如果您想使用测试数据库而不是开发数据库,您应该创建测试数据库并让后端应用程序能够找到并使用测试数据库。

Kareem, I suggest you create your Settings instance from one or another .env file, based on an ENVIRONMENT variable: Kareem,我建议您根据ENVIRONMENT变量从一个或另一个.env文件创建您的Settings实例:

import os
import sys

import pydantic


class Settings(pydantic.BaseSettings):
    database: str
    user: str
    port: int
    password: str
    expiray: int
    algorithm: str
    secret_key: str


try:
    ENVIRONMENT = os.environ['ENVIRONMENT']
except KeyError:
    print('make sure to set an "ENVIRONMENT" env var')
    sys.exit()

    
settings = Settings(_env_file=f'{ENVIRONMENT}.env', _env_file_encoding='utf-8')

This way, if you want to work with the testing database, you can do $ export ENVIRONMENT=test and it will load the settings from a file called test.env .这样,如果您想使用测试数据库,您可以执行$ export ENVIRONMENT=test ,它将从名为test.env的文件中加载设置。

Does that make sense?那有意义吗? Here are the docs for pydantic 's dotenv support for BaseSettings subclasses. 这是pydantic 对pydantic子类的dotenv支持的BaseSettings

As an aside, since you're interested in doing as much as you can without the use of an ORM and perhaps other dependencies, you really don't need pydantic for your purposes: You could simply change the above to something like:顺便说一句,由于您有兴趣在不使用 ORM 和其他依赖项的情况下尽可能多地做事,因此您真的不需要pydantic来实现您的目的:您可以简单地将上面的内容更改为:


import os
import sys
import types

import dotenv


try:
    ENVIRONMENT = os.environ['ENVIRONMENT']
except KeyError:
    print('make sure to set an "ENVIRONMENT" env var')
    sys.exit()


db_settings_dict = dotenv.dotenv_values(f"{ENVIRONMENT}.env")

# to get dot notation as in your example
settings = types.SimpleNamespace(**db_settings_dict)

where test.env contains things like其中test.env包含类似

database=hey.there.com:8768
user=kareem
...

Below is the Script I was written to control the ENV variable from the.env file, before running the unicorn server you would load the.env file based on the ENV mode to determine what kinds of modes are working on then use conditions to set up the corresponding DB path and name.下面是我为控制 .env 文件中的 ENV 变量而编写的脚本,在运行 unicorn 服务器之前,您将根据 ENV 模式加载 .env 文件以确定正在使用哪种模式,然后使用条件进行设置对应的数据库路径和名称。


import os
import sys
from colored import fg
from os import environ, path
from dotenv import load_dotenv, set_key
import dotenv


def unknown(option, args=None):
    color = fg('red')
    if args:
        print(color + f'Unknown arguments: -{args}')
    else:
        print(color + f'Unknown option: -{option}')
    print("usage: python3 config.py [option] [arguments]")
    print("Try `python3 config.py --help for more information")
    color = fg('white')
    print(color)


def version():
    basedir = path.abspath(path.dirname(__file__))
    load_dotenv(path.join(basedir, '.env'))
    color = fg('blue')
    print(color + '[VERSION]: ' + environ.get('VER'))
    color = fg('white')
    print(color)


def env():
    basedir = path.abspath(path.dirname(__file__))
    load_dotenv(path.join(basedir, '.env'))
    color = fg('blue')
    print(color + '[ENV]: ' + environ.get('ENV'))
    color = fg('white')
    print(color)


def set_env(env):
    dotenv_file = dotenv.find_dotenv()

    basedir = path.abspath(path.dirname(__file__))
    load_dotenv(path.join(basedir, '.env'))
    color = fg('blue')
    print(color + f"[Updating ENV] ... ... from {environ.get('ENV')} to {env}")
    os.environ["ENV"] = env
    set_key(dotenv_file, 'ENV', os.environ['ENV'])
    print("[Successfully Update the 'ENV' from .env]")
    color = fg('white')
    print(color)


def doc():
    color = fg('blue')
    print(color + "usage: python3 config.py [option] [arguments]")

    read_me = """
    -v                  : current project version
    -env                : current project environment
    -set ENV={env}      : set project env 'DEV' or 'PROD'
    """
    print(read_me)
    color = fg('white')
    print(color)


def action_handler(option, args):
    if option == '-set':
        args_list = args.split('=')
        if args_list[0] == 'ENV' and (args_list[1] == 'DEV' or args_list[1] == 'PROD'):
            set_env(args_list[1])
        else:
            unknown(option=option, args=args)
    else:
        unknown(option=option)


argvs = len(sys.argv)

if argvs == 1:
    doc()
elif argvs == 2:
    option = sys.argv[1]
    if option == '--help':
        doc()
    elif option == '-v':
        version()
    elif option == '-env':
        env()
    else:
        unknown(option)
elif argvs == 3:
    option, args = sys.argv[1], sys.argv[2]
    action_handler(option, args)
else:
    pass

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

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