Pytest und PostgreSQL: Frische Datenbank für jeden Test

WBOY
Freigeben: 2024-08-19 16:43:42
Original
276 Leute haben es durchsucht

Pytest and PostgreSQL: Fresh database for every test

In Pytest, dem beliebtesten Python-Test-Framework aller, ist ein Fixture ein wiederverwendbarer Codeabschnitt, deretwasvor Beginn des Tests arrangiert 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 bereinigt wird , 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 vor dem Test eine leere Datenbankoptional
  • Migrationen anwenden oder Testdaten erstellen
  • vor dem Test
  • Stellen Sie eine Verbindung zur Testdatenbank her
  • zum Test
  • Testdatenbank fallen lassen
  • nach dem Test (auch im Fehlerfall)
  • Jede Testmethode, die dies anfordert, indem sie ein Testmethodenargument auflistet:

def test_create_admin_table(test_db): ...
Nach dem Login kopieren

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): # 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)
Nach dem Login kopieren

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 │ └── sales │ └── new_user.py ├── tests │ ├── conftest.py │ └── sales │ └── test_new_user.py ├── requirements.txt └── yoyo.ini
Nach dem Login kopieren

Wenn Sie eine Migrationsbibliothek wie das fantastische Yoyo verwenden, befinden sich Migrationsskripte wahrscheinlich in migrations/:

├── migrations ├── 20240816_01_Yn3Ca-sales-user-user-add-last-run-table.py ├── ...
Nach dem Login kopieren

Konfiguration

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

    Verbindungs-URL
  • – (ohne Datenbank)
  • Testdatenbankname
  • – wird für jeden Test neu erstellt(optional)
  • Migrationsordner
  • – Migrationsskripte zur Anwendung für jeden Test
  • Pytest verfügt über einen natürlichen Ort conftest.py zum Teilen von Fixtures über mehrere Dateien hinweg. Dort wird auch die Gerätekonfiguration angezeigt:

# Without DB name! TEST_DB_URL = "postgresql://localhost" TEST_DB_NAME = "test_tuvok" TEST_DB_MIGRATIONS_DIR = str(Path(__file__, "../../migrations").resolve())
Nach dem Login kopieren

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 der

PostgreSQL- und Psycopg-Bibliothek

schreiben Sie das Fixture in 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)')
Nach dem Login kopieren

Erstellen Sie eine Migrationseinrichtung

In unserem Fall verwenden wir

Yoyo-Migrationen

. Schreiben Sie apply migrations als ein weiteres Fixture mit dem Namen 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))
Nach dem Login kopieren

Wenn Sie Migrationen auf jede Testdatenbank anwenden möchten

, benötigen Sie Yoyo Fixture für test_db Fixture:

@pytest.fixture def test_db(yoyo): ...
Nach dem Login kopieren

Um die Migration nur auf einige Tests anzuwenden

, erfordern Sie Yoyo einzeln:

def test_create_admin_table(test_db, yoyo): ...
Nach dem Login kopieren

Abschluss

Der Aufbau 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 Datenbank-Testsuite geholfen. Hinterlassen Sie mir Ihre Frage gerne in den Kommentaren und viel Spaß beim Codieren!

Das obige ist der detaillierte Inhalt vonPytest und PostgreSQL: Frische Datenbank für jeden Test. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!