jeudi 18 février 2021

How do I prepare a rollback-friendly test datebase?

I have a PostgreSQL database filled with fake data for test automation with pytest. Basically, I will run each test against the test database, check the result, rollback everything so that the test environment doesn't change, then run the next test, and so on and so forth. For obvious reasons, the application code under test (it's a Flask application FWIW) involves numerous pairs of BEGIN/COMMIT, and I don't want to change that.

Currently, my fixture looks like

@pytest.fixture
def app():
    app = create_app(TestConfig)
    app.config["TESTING"] = True

    cur = app.db_postgres.cursor()
    cur.execute("BEGIN")

    with app.app_context():
        yield app

    cur.execute("ROLLBACK")

I tried to address the problem with transactions, but PostgreSQL 13 doesn't seem to support autonomous transactions. More concretely, the second COMMIT; gives me a WARNING: there is already a transaction in progress, and the INSERT operation persists to the database as soon as COMMIT; is executed, rendering the final ROLLBACK; useless.

-- Setup
BEGIN;

-- Application code can do whatever they want
BEGIN;
INSERT INTO test_foo(bar) VALUES (42);
COMMIT;
SELECT bar FROM test_foo;  -- assert the result is 42

-- Teardown
ROLLBACK;

I surely can do a full backup of the test database and restore it once for each test, but that would be time-consuming and considerably slow down our development cycle. How do I have a test database that is easy to rollback?

Aucun commentaire:

Enregistrer un commentaire