Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Comment thread
jgaffiot marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
DATABASE_URL=postgresql://bookstore:bookstore@localhost:5432/bookstore
PAYMENT_API_URL=https://absolutely-non-existing.fake/v666
PAYMENT_API_KEY=sk_test_changeme
EMAIL_SMTP_HOST=localhost
EMAIL_SMTP_PORT=1025
EMAIL_FROM=shop@bookstore.local
46 changes: 46 additions & 0 deletions .github/workflows/ci.yml

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question(blocking): should we also offer a GitLab (at least non-GitHub) option like last year ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The abstract asks for GitHUB or GitLab, so we need to provide it.

Decision : add a .gitlab-ci.yml and push the repo as a mirror on gitlab

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: CI

on: [push]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
# No caching — reinstalls all dependencies on every run

- name: Install dependencies
run: pip install -e ".[test]"
# Uses pip instead of uv; no lock file pinning

- name: Start PostgreSQL
run: |
sudo systemctl start postgresql
sudo -u postgres psql -c "CREATE USER bookstore WITH PASSWORD 'bookstore';"
sudo -u postgres psql -c "CREATE DATABASE bookstore OWNER bookstore;"
# No wait/health check — tests may start before DB is ready

- name: Run migrations
run: alembic upgrade head
# Will fail silently if DB isn't up yet

- name: Start app
run: uvicorn app.main:app --host 0.0.0.0 --port 8000 &
# No health check — tests start immediately, race condition

- name: Run tests
run: pytest tests/ -v
env:
# Payment API key hardcoded in the workflow — will fail without it
PAYMENT_API_KEY: ${{ secrets.PAYMENT_API_KEY }}
# No DATABASE_URL override — uses the hardcoded default from config.py

# No coverage reporting
# No test result artifacts
# No notification on failure
5 changes: 3 additions & 2 deletions .gitignore
Comment thread
jgaffiot marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
# .idea/
.idea/

# Abstra
# Abstra is an AI-powered process automation framework.
Expand All @@ -199,7 +199,8 @@ cython_debug/
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/
.vscode/

# Temporary file for partial code execution
tempCodeRunnerFile.py

Expand Down
49 changes: 49 additions & 0 deletions ABSTRACT.md
Comment thread
jgaffiot marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Getting out of testing hell!

We know we should write automated tests. But too often, it is a real chore:
they may be slow, unreliable, difficult to run, to maintain, even to write!
Why is it so hard? How to take back control?

For that, you will work on a realistic project: a Python app with FastAPI backend,
a PostgreSQL database, configuration files, third-party APIs, ...
and tests that are awful.

You will review:

the quality culture of the project
how it is architectured
the existing tests
and the code quality

Then you will prepare the plan:

your own test pyramid / strategy
testing tools needed
essential scenarios
the CI to have your back

And start coding:

updating the existing tests
adding new tests using powerful tooling
minimal refactoring to enable testing
creating fakes/mocks/simulators to enable testing

You'll leave able to:

diagnose what makes tests slow or convoluted
design a pragmatic test strategy for your codebase
implement reliable tests, with fakes and testcontainers
refactor just enough to make code testable

It will be around 65% hands-on, and 35% guided analysis.
The first two parts will take the first half of the session, so that you have plenty of
time to actually implement the strategy during the second half.
The code repository will stay available to you after the workshop,
along with an example of the end-result.

Setup :

uv
(optional) docker or podman, to run TestContainers
(optional) a GitHub or GitLab account, to run CI
35 changes: 35 additions & 0 deletions AGENTS.md
Comment thread
jgaffiot marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Repo purpose

This is workshop material — *"Getting out of the testing hell"* — for intermediate
Python developers. Participants are handed a FastAPI + PostgreSQL bookstore app with
deliberately bad tests and a testable-but-not-tested architecture, and their job during
the workshop is to diagnose the problems and fix them themselves (see `README.md` and
`ABSTRACT.md` for the full brief).

## Layout

- `app/`, `tests/`, `.github/workflows/ci.yml` (root) — the **workshop starting point**.
Intentionally flawed: brittle/order-dependent tests, un-injectable dependencies, a
broken CI pipeline. This is what participants work on.
- `solution/` — the **reference solution**: refactored app code and rewritten tests
showing one valid end-state (dependency injection, Testcontainers, fakes, fixed CI).
It exists as an answer key participants can compare against *after* attempting the
exercise themselves, per `solution/README.md`.

## Important: don't spoil the workshop

If you're helping someone who is doing (or facilitating) this workshop — diagnosing
`tests/`, refactoring `app/`, writing new tests, fixing the root CI — **do not reach
into `solution/` to solve it for them.** Don't copy code from `solution/`, don't paste
its fixtures/fakes/services into the root `app/`/`tests/`, and don't reveal its
contents unprompted. The value of the workshop is in participants finding the seams
and design themselves.

It's fine to:
- Discuss `solution/` explicitly if the user asks to see it, compare against it, or
says they're past the exercise / just reviewing the answer key.
- Work on `solution/` directly when asked to (e.g. this session's CI caching change).
- Point out that a reference solution exists, without detailing its contents.

When in doubt about which mode you're in (doing the exercise vs. maintaining the
answer key), ask.
1 change: 1 addition & 0 deletions CLAUDE.md
Loading
Loading