Skip to main content

Module db

Module db 

Source
Available on crate features model-mysql or model-postgres or model-sqlite only.
Expand description

A database per test that leaves nothing behind.

TestDb hands out a DbPool (deref, or TestDb::pool for a clone the app’s state can own), so a test builds its app on it and drives it with TestClient as usual:

use rust_web_server::test_client::TestDb;

let db = TestDb::sqlite().migrations("migrations").await?;
db.execute("INSERT INTO notes (text) VALUES ('hi')", &[]).await?;
let app_state_pool = db.pool(); // cheap clone, same database

How each backend isolates a test:

  • SQLite (TestDb::sqlite): a fresh in-memory database, its own per TestDb, with the migrations applied. It disappears when the last clone of the pool is dropped. Nothing is shared between tests, so they run in parallel.
  • PostgreSQL / MySQL (TestDb::postgres, TestDb::mysql, or the _from_env forms reading RWS_TEST_POSTGRES_URL / RWS_TEST_MYSQL_URL): the migrations are applied to the database for real (once per process and directory, serialized), then the pool is pinned to one connection that is inside a transaction from the moment it connects. The test’s writes stay in that transaction, which is never committed: TestDb::rollback rolls it back, and dropping the TestDb closes the pool, so the server rolls it back when the connection goes.

Limits of the transaction (the usual ones for transactional tests):

  • Use a database of its own for tests: the schema (migrations) persists.
  • One connection: code that holds two connections at once (two DbTransactions alive together, a query while iterating another) waits for itself. DbPool::begin/transaction work — sqlx turns them into savepoints inside the test’s transaction, so their commit commits nothing.
  • Raw COMMIT / BEGIN statements, and on MySQL DDL (CREATE, ALTER, DROP, TRUNCATE commit implicitly), do end the transaction: whatever ran before them stays. Put such statements in migrations.
  • On PostgreSQL a failed statement aborts the test’s transaction; every later statement fails until the test ends. Run statements expected to fail inside DbPool::transaction (a savepoint) instead.
  • Concurrent tests on the same rows can block each other on row locks until one ends.

Structs§

TestDb
A database for one test; see the module docs.
TestDbBuilder
A TestDb being set up: add migration directories, then .await it (or call build).