Interview question
Verify a PostgreSQL constraint with pytest and Testcontainers
Runs a migration-backed pytest integration test against PostgreSQL and proves case-insensitive email uniqueness.
TL;DR
Runs a migration-backed pytest integration test against PostgreSQL and proves case-insensitive email uniqueness.
pytest fixture scope, Testcontainers, production migrations, PostgreSQL-specific constraints, transaction cleanup, and flush timing.
Practice the problem like a real interview: restate, reason, implement, and test.
Write an integration test proving the production migration enforces case-insensitive email uniqueness. Start PostgreSQL with Testcontainers, run normal Alembic migrations, insert User@Example.com, then prove user@example.com violates the database constraint. Do not replace the rule with SQLite or test-only DDL.
Move to the linked follow-up, next path step, prerequisite, or deeper variant.
Practice the next layer of the same subject.
insert User@Example.com -> succeeds
insert user@example.com -> IntegrityError on flush/commit
engine dialect -> postgresql
alembic upgrade head.import pytest
from sqlalchemy import create_engine, text
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from testcontainers.postgres import PostgresContainer
@pytest.fixture(scope="session")
def postgres_engine():
with PostgresContainer("postgres:17-alpine") as postgres:
engine = create_engine(postgres.get_connection_url())
run_alembic_upgrade(engine, "head")
yield engine
engine.dispose()
def test_email_uniqueness_is_case_insensitive(postgres_engine):
assert postgres_engine.dialect.name == "postgresql"
with Session(postgres_engine) as session:
session.add(User(email="User@Example.com"))
session.commit()
session.add(User(email="user@example.com"))
with pytest.raises(IntegrityError):
session.flush()
session.rollback()
The test performs two inserts and one indexed uniqueness check. Container startup dominates runtime, so fixture reuse must be balanced with deterministic isolation.
Spot a weak answer, missing edge case, or clearer explanation? Send it in.
Say thanks with a standalone, one-time $5 contribution. No account required.