„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Pytest und PostgreSQL: Frische Datenbank für jeden Test

Pytest und PostgreSQL: Frische Datenbank für jeden Test

Veröffentlicht am 21.08.2024
Durchsuche:568

Pytest and PostgreSQL: Fresh database for every test

In Pytest, dem beliebtesten Python-Testframework aller, ist ein Fixture ein wiederverwendbarer Codeabschnitt, der etwas anordnet, bevor der Test beginnt, und nach dem Beenden aufräumt. Zum Beispiel eine temporäre Datei oder einen temporären Ordner, eine Setup-Umgebung, das Starten eines Webservers usw. In diesem Beitrag schauen wir uns an, wie man ein Pytest-Fixture erstellt, das eine Testdatenbank (leer oder mit bekanntem Status) erstellt, die abgerufen wird bereinigt, sodass jeder Test auf einer völlig sauberen Datenbank ausgeführt werden kann.

Die Ziele

Wir werden mit Psycopg 3 ein Pytest-Gerät erstellen, um die Testdatenbank vorzubereiten und zu bereinigen. Da eine leere Datenbank zum Testen selten hilfreich ist, werden wir optional Yoyo-Migrationen anwenden (zum Zeitpunkt des Schreibens ist die Website nicht verfügbar, gehen Sie zum Snapshot von archive.org), um sie aufzufüllen.

Die Anforderungen für das Pytest-Fixture namens test_db, das in diesem Blogbeitrag erstellt wurde, sind also:

  • Testdatenbank löschen, falls vor dem Test vorhanden
  • erstellen Sie eine leere Datenbank vor dem Test
  • optional
  • Migrationen anwenden oder Testdaten erstellen vor dem Test
  • Stellen Sie eine Verbindung zur Testdatenbank her zum Test
  • Testdatenbank löschen nach dem Test (auch im Fehlerfall)
Jede Testmethode, die dies anfordert, indem sie ein Testmethodenargument auflistet:


def test_create_admin_table(test_db): ...
def test_create_admin_table(test_db):
    ...
Erhält eine reguläre Psycopg-Verbindungsinstanz, die mit der Test-DB verbunden ist. Der Test kann alles tun, was er benötigt, wie bei der allgemeinen Verwendung von Psycopg, z. B.:


def test_create_admin_table(test_db): # Öffnen Sie einen Cursor, um Datenbankoperationen auszuführen cur = test_db.cursor() # Übergeben Sie Daten, um Platzhalter für eine Abfrage zu füllen und Psycopg ausführen zu lassen # die richtige Konvertierung (keine SQL-Injections!) cur.execute( „INSERT INTO test (num, data) VALUES (%s, %s)“, (100, „abc'def“)) # Fragen Sie die Datenbank ab und erhalten Sie Daten als Python-Objekte. cur.execute("SELECT * FROM test") cur.fetchone() # wird zurückgeben (1, 100, „abc'def“) # Sie können „cur.fetchmany()“ und „cur.fetchall()“ verwenden, um eine Liste zurückzugeben Anzahl mehrerer Datensätze oder sogar Iteration am Cursor für Aufnahme in cur: drucken (aufzeichnen)
def test_create_admin_table(test_db):
    ...

Motivation & Alternativen Es sieht so aus, als gäbe es einige Pytest-Plugins, die PostgreSQL-Fixtures für Tests versprechen, die auf Datenbanken basieren. Sie könnten für Sie gut funktionieren.
Ich habe pytest-postgresql ausprobiert, was dasselbe verspricht. Ich habe es versucht, bevor ich mein eigenes Fixture geschrieben habe, aber ich konnte es nicht für mich zum Laufen bringen. Vielleicht, weil ihre Dokumente für mich sehr verwirrend waren.

Noch eins, pytest-dbt-postgres, ich habe es überhaupt nicht versucht.



Layout der Projektdatei

In klassischen Python-Projekten befinden sich die Quellen in src/ und Tests in Tests/:


├── src │ └── tuvok │ ├── __init__.py │ └── Verkauf │ └── new_user.py ├── Tests │ ├── conftest.py │ └── Verkauf │ └── test_new_user.py ├── Anforderungen.txt └── yoyo.ini
def test_create_admin_table(test_db):
    ...
Wenn Sie eine Migrationsbibliothek wie das fantastische Yoyo verwenden, befinden sich Migrationsskripte wahrscheinlich in migrations/:


├── Migrationen ├── 20240816_01_Yn3Ca-sales-user-user-add-last-run-table.py ├── ...
def test_create_admin_table(test_db):
    ...
Konfiguration

Unser Test-DB-Gerät benötigt nur eine sehr kleine Konfiguration:

  • Verbindungs-URL – (ohne Datenbank)
  • Name der Testdatenbank – wird für jeden Test neu erstellt
  • (optional)
  • Migrationsordner – Migrationsskripte, die für jeden Test angewendet werden sollen
Pytest verfügt über einen natürlichen Ort conftest.py zum Teilen von Fixtures über mehrere Dateien hinweg. Dort wird auch die Fixture-Konfiguration abgelegt:


# Ohne DB-Namen! TEST_DB_URL = "postgresql://localhost" TEST_DB_NAME = "test_tuvok" TEST_DB_MIGRATIONS_DIR = str(Path(__file__, "../../migrations").resolve())
def test_create_admin_table(test_db):
    ...
Sie können diese Werte über die Umgebungsvariable oder was auch immer für Ihren Fall geeignet ist, festlegen.

Erstellen Sie test_db-Fixture

Mit Kenntnissen von

PostgreSQL und der Psycopg-Bibliothek schreiben Sie das Fixture in conftest.py:

@pytest.fixture def test_db(): # autocommit=True, keine Transaktion starten, da DATENBANK ERSTELLEN/ENTFERNEN # kann nicht in einem Transaktionsblock ausgeführt werden. mit psycopg.connect(TEST_DB_URL, autocommit=True) als conn: cur = conn.cursor() # Test-DB erstellen, vorher löschen cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB_NAME}" WITH (FORCE)') cur.execute(f'CREATE DATABASE "{TEST_DB_NAME}"') # Gibt eine (neue) Verbindung zur gerade erstellten Test-DB zurück # Leider können Sie die Datenbank für eine bestehende Psycopg-Verbindung nicht direkt ändern. Sobald eine Verbindung zu einer bestimmten Datenbank hergestellt wurde, wird sie an diese Datenbank gebunden. mit psycopg.connect(TEST_DB_URL, dbname=TEST_DB_NAME) als conn: Ertragsverb cur.execute(f'DROP DATABASE IF EXISTS "{TEST_DB_NAME}" WITH (FORCE)')
def test_create_admin_table(test_db):
    ...
Erstellen Sie eine Migrationseinrichtung

In unserem Fall verwenden wir

Yoyo-Migrationen. Schreiben Sie Apply-Migrationen als ein weiteres Fixture mit dem Namen yoyo:

@pytest.fixture def yoyo(): # Yoyo erwartet `driver://user:pass@host:port/database_name?param=value`. # In der übergebenen URL müssen wir URL = ( urlparse(TEST_DB_URL) . # 1) Ändern Sie den Treiber (Schema-Teil) mit „postgresql psycopg“, um ihn zu verwenden # psycopg 3 (nicht 2, was „postgresql psycopg2“ ist) _replace(scheme="postgresql psycopg") . # 2) Datenbank in Testdatenbank ändern (in der Migrationen angewendet werden) _replace(path=TEST_DB_NAME) .geturl() ) backend = get_backend(url) migrations = read_migrations(TEST_DB_MIGRATIONS_DIR) wenn len(migrations) == 0: raise ValueError(f"Keine Yoyo-Migrationen gefunden in '{TEST_DB_MIGRATIONS_DIR}'") mit backend.lock(): backend.apply_migrations(backend.to_apply(migrations))
def test_create_admin_table(test_db):
    ...
Wenn Sie

Migrationen auf jede Testdatenbank anwenden möchten, benötigen Sie ein Yoyo-Fixture für test_db-Fixture:

@pytest.fixture def test_db(yoyo): ...
def test_create_admin_table(test_db):
    ...
Um

die Migration nur auf einige Tests anzuwenden, erfordern Sie Yoyo einzeln:

def test_create_admin_table(test_db, yoyo): ...
def test_create_admin_table(test_db):
    ...
Abschluss

Das Erstellen einer eigenen Vorrichtung, um Ihren Tests eine saubere Datenbank zu bieten, war für mich eine lohnende Erfahrung, die es mir ermöglichte, tiefer in Pytest und Postgres einzutauchen.

Ich hoffe, dieser Artikel hat Ihnen bei Ihrer eigenen Datenbanktestsuite geholfen. Hinterlassen Sie mir Ihre Frage gerne in den Kommentaren und viel Spaß beim Codieren!

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/liborjelinek/pytest-and-postgresql-fresh-database-for-every-test-4eni?1 Bei Verstößen wenden Sie sich zum Löschen bitte an [email protected] Es
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3