Rollback-Transaktionen funktionieren nicht mit py.test und Flask

8

Ich verwende py.test, um meine Flask-Anwendung zu testen, aber ich bekomme IntegrityError, weil ich das gleiche Modell in zwei verschiedenen Tests erstelle.

Ich benutze postgreSQL 9.3.5 und Flask-SQLAlchemy 1.0.

BEARBEITEN Ich habe meine Sitzung mit der Antwort von Jeremy Allen aktualisiert und viele Fehler behoben. Wie auch immer es scheint, wenn ich das Benutzergerät benutze, bekomme ich immer noch IntegrityErrors

Fehler

%Vor%

conftest.py

%Vor%

Tests, die fehlschlagen

%Vor%

Tests, die bestanden haben

%Vor%     
Siecje 24.10.2014, 19:41
quelle

3 Antworten

14

Es sieht so aus, als ob Sie versuchen, einer Sitzung in eine externe Transaktion beitreten und Sie verwenden flask-sqlalchemy.

Ihr Code funktioniert nicht wie erwartet, da die Sitzung tatsächlich eine andere Verbindung verwendet als diejenige, mit der Sie die Transaktion starten.

1. Sie müssen die Sitzung an die Verbindung binden

Wie in dem oben verlinkten Beispiel. Eine schnelle Änderung an Ihrem Code in conftest.py sollte es tun:

%Vor%

Leider aufgrund von SignallingSession von flask-sqlalchemy (wie bei v2.0), wird Ihr 'bind'-Argument außer Kraft gesetzt!

Das liegt daran, dass SignallingSession das Argument 'binds' so gesetzt hat, dass es Vorrang vor unserem Argument 'bind' hat, und es bietet uns keine Möglichkeit, unser eigenes Argument 'binds' anzugeben.

Es gibt eine GitHub-Pull-Anfrage von Dezember 2013, bei der jemand anderes das gleiche Problem hatte. p>

2. Tweak Flasche-sqlalchemy

Wir können SignallingSession ableiten, damit wir tun können, was wir wollen:

%Vor%

Und dann Unterklasse SQLAlchemy (die Hauptflasche-sqlalchemy-Klasse), um unsere SessionWithBinds anstelle von SignallingSession zu verwenden

%Vor%

Nun müssen Sie diese Klasse anstelle von SQLAlchemy verwenden:

%Vor%

Und schließlich, wieder in unserer conftest.py geben Sie eine neue 'bindet':

%Vor%

Jetzt sollten Ihre Transaktionen wie erwartet zurückgesetzt werden.

Das ist alles ein bisschen kompliziert ...

Anstatt all das zu tun, könntest du versuchen zu verwenden Session.begin_nested . Es erfordert, dass Ihre Datenbank SQL SAVEPOINTs unterstützt (PostgreSQL tut).

Ändern Sie Ihre conftest.py-Fixture:

%Vor%

Weitere Informationen zur Verwendung von SAVEPOINT s in SQLAlchemy: Ссылка

Dies ist ziemlich einfach, funktioniert aber solange der Code, den Sie testen, nicht rollback selbst aufruft. Wenn dies ein Problem ist, werfen Sie einen Blick auf den Code hier in den SQLAlchemy-Dokumenten unter dem Titel" Unterstützung von Tests mit Rollbacks

    
Jeremy Allen 29.10.2014, 06:41
quelle
1

Sie haben nicht wirklich gesagt, was Sie zum Verwalten der Datenbank verwenden, es gibt keine Ahnung, welche Bibliothek hinter _db oder einer der Modellklassen steht.

Aber unabhängig davon würde ich vermuten, dass der Aufruf session.commit() wahrscheinlich an dem Grund beteiligt ist, aus dem die Transaktion ausgeführt wird. Letztendlich müssen Sie die Dokumente lesen, in denen session.commit() in dem von Ihnen verwendeten Framework funktioniert.

    
flub 28.10.2014 20:40
quelle
1

Der Schlüssel besteht darin, Ihre Tests innerhalb einer verschachtelten Sitzung auszuführen und dann nach der Ausführung jedes Tests einen Rollback durchzuführen (dies setzt auch voraus, dass keine Abhängigkeiten zwischen Ihren Tests bestehen).

Ich schlage vor, den folgenden Ansatz zu verwenden, indem Sie jeden Ihrer Tests innerhalb einer verschachtelten Transaktion ausführen:

%Vor%     
Eddie Forson 27.01.2018 18:46
quelle