ホームページ > バックエンド開発 > Python チュートリアル > Pytest と PostgreSQL: すべてのテストに使用できる最新のデータベース

Pytest と PostgreSQL: すべてのテストに使用できる最新のデータベース

WBOY
リリース: 2024-08-19 16:43:42
オリジナル
490 人が閲覧しました

Pytest and PostgreSQL: Fresh database for every test

誰もが好む Python テスト フレームワークである Pytest では、フィクスチャは、テストが開始される前に 何か を配置し、終了後にクリーンアップする再利用可能なコードです。たとえば、一時ファイルやフォルダー、環境のセットアップ、Web サーバーの起動などです。この投稿では、テスト データベース (空または既知の状態) を作成する Pytest フィクスチャの作成方法を見ていきます。クリーンアップされ、完全にクリーンなデータベースで各テストを実行できるようになります

目標

Psycopg 3 を使用して Pytest フィクスチャを作成し、テスト データベースを準備およびクリーンアップします。空のデータベースがテストに役立つことはほとんどないため、必要に応じて Yoyo 移行 (この記事の執筆時点では Web サイトがダウンしており、archive.org スナップショットに移動) を適用してデータベースを埋めます。

このブログ投稿で作成した test_db という名前の Pytest フィクスチャの要件は次のとおりです。

  • テスト前にテストデータベースが存在する場合はを削除します
  • テストの前に空のデータベースを作成します
  • オプションで、テストの前に移行を適用するか、テスト データを作成します
  • テストデータベースへの接続を提供します をテスト
  • に提供します
  • テスト後にテスト データベースを削除します (失敗した場合でも)

テスト メソッドの引数をリストしてリクエストするテスト メソッド:

def test_create_admin_table(test_db):
    ...
ログイン後にコピー

テスト DB に接続された通常の Psycopg Connection インスタンスを受け取ります。テストは、単純な Psycopg の一般的な使用法と同様に、必要なことを何でも実行できます。例:

def test_create_admin_table(test_db):
    # Open a cursor to perform database operations
    cur = test_db.cursor()

    # Pass data to fill a query placeholders and let Psycopg perform
    # the correct conversion (no SQL injections!)
    cur.execute(
        "INSERT INTO test (num, data) VALUES (%s, %s)",
        (100, "abc'def"))

    # Query the database and obtain data as Python objects.
    cur.execute("SELECT * FROM test")
    cur.fetchone()
    # will return (1, 100, "abc'def")

    # You can use `cur.fetchmany()`, `cur.fetchall()` to return a list
    # of several records, or even iterate on the cursor
    for record in cur:
        print(record)
ログイン後にコピー

動機と選択肢
データベースに依存するテストに PostgreSQL フィクスチャを約束する Pytest プラグインがいくつかあるようです。それらはあなたにとってうまくいくかもしれません。

同じことを約束する pytest-postgresql を試しました。独自のフィクスチャを作成する前に試してみましたが、うまく動作させることができませんでした。おそらく、彼らのドキュメントが私にとって非常にわかりにくかったからでしょう。

もう 1 つの pytest-dbt-postgres は、まったく試していません。


プロジェクトファイルのレイアウト

古典的な Python プロジェクトでは、ソースは src/ に存在し、テストは testing/:

├── src
│   └── tuvok
│       ├── __init__.py
│       └── sales
│           └── new_user.py
├── tests
│   ├── conftest.py
│   └── sales
│       └── test_new_user.py
├── requirements.txt
└── yoyo.ini
ログイン後にコピー

幻想的な Yoyo のような移行ライブラリを使用する場合、移行スクリプトはおそらく migrations/:
にあります。

├── migrations
    ├── 20240816_01_Yn3Ca-sales-user-user-add-last-run-table.py
    ├── ...
ログイン後にコピー

構成

私たちのテスト DB フィクスチャには、非常に小さな構成が必要です:

  • 接続 URL - (データベースなし)
  • テスト データベース名 - テストごとに再作成されます
  • (オプション) 移行フォルダー - すべてのテストに適用する移行スクリプト

Pytest には、複数のファイル間でフィクスチャを共有するための conftest.py という自然な場所があります。フィクスチャ設定もそこに移動します:

# Without DB name!
TEST_DB_URL = "postgresql://localhost"
TEST_DB_NAME = "test_tuvok"
TEST_DB_MIGRATIONS_DIR = str(Path(__file__, "../../migrations").resolve())
ログイン後にコピー

これらの値は環境変数から設定することも、状況に応じて設定することもできます。

test_db フィクスチャの作成

PostgreSQL および Psycopg ライブラリ の知識を基に、conftest.py にフィクスチャを作成します。

@pytest.fixture
def test_db():
    # autocommit=True start no transaction because CREATE/DROP DATABASE
    # cannot be executed in a transaction block.
    with psycopg.connect(TEST_DB_URL, autocommit=True) as conn:
        cur = conn.cursor()

        # create test DB, drop before
        cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB_NAME}" WITH (FORCE)')
        cur.execute(f'CREATE DATABASE "{TEST_DB_NAME}"')

        # Return (a new) connection to just created test DB
        # Unfortunately, you cannot directly change the database for an existing Psycopg connection. Once a connection is established to a specific database, it's tied to that database.
        with psycopg.connect(TEST_DB_URL, dbname=TEST_DB_NAME) as conn:
            yield conn

        cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB_NAME}" WITH (FORCE)')
ログイン後にコピー

移行フィクスチャの作成

私たちの場合、Yoyo マイグレーションを使用します。マイグレーションの適用を yoyo という別のフィクスチャとして記述します:

@pytest.fixture
def yoyo():
    # Yoyo expect `driver://user:pass@host:port/database_name?param=value`.
    # In passed URL we need to
    url = (
        urlparse(TEST_DB_URL)
        .
        # 1) Change driver (schema part) with `postgresql+psycopg` to use
        # psycopg 3 (not 2 which is `postgresql+psycopg2`)
        _replace(scheme="postgresql+psycopg")
        .
        # 2) Change database to test db (in which migrations will apply)
        _replace(path=TEST_DB_NAME)
        .geturl()
    )

    backend = get_backend(url)
    migrations = read_migrations(TEST_DB_MIGRATIONS_DIR)

    if len(migrations) == 0:
        raise ValueError(f"No Yoyo migrations found in '{TEST_DB_MIGRATIONS_DIR}'")

    with backend.lock():
        backend.apply_migrations(backend.to_apply(migrations))
ログイン後にコピー

すべてのテスト データベースに移行を適用する場合は、test_db フィクスチャにヨーヨー フィクスチャが必要です:

@pytest.fixture
def test_db(yoyo):
    ...
ログイン後にコピー

一部のテストのみに移行を適用するには、ヨーヨーを個別に必要とします:

def test_create_admin_table(test_db, yoyo):
    ...
ログイン後にコピー

結論

テストにクリーンなデータベースを提供するための独自のフィクスチャを構築することは、私にとって Pytest と Postgres の両方をより深く掘り下げることができる貴重な経験でした。

この記事が独自のデータベース テスト スイートに役立つことを願っています。お気軽にコメント欄に質問を残していただき、コーディングを楽しんでください!

以上がPytest と PostgreSQL: すべてのテストに使用できる最新のデータベースの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート