Bank Account
Level: Intermediate 30–60 minConcepts: StateValidationEdge CasesBoundaries
Solutions: C# | TypeScript | Python
Create a bank account that tracks transactions and enforces business rules.
Requirements
- Open Account — create an account with an initial balance of 0
- Deposit — add funds to the account
- Amount must be positive
- Records the transaction with date and amount
- Withdraw — remove funds from the account
- Amount must be positive
- Cannot withdraw more than current balance (no overdraft)
- Records the transaction with date and amount
- Get Balance — returns the current balance
- Print Statement — returns a formatted statement showing all transactions
Statement format:
Date | Amount | Balance
2026-01-15 | 500.00 | 500.00
2026-01-20 | -100.00 | 400.00
2026-01-25 | 200.00 | 600.00
Transactions are printed in chronological order with running balance.
Test Cases
| Action | Amount | Expected Balance | Notes |
|---|---|---|---|
| Deposit | 500 | 500 | |
| Deposit | 200 | 700 | |
| Withdraw | 100 | 600 | |
| Withdraw | 700 | 600 | Rejected — insufficient funds |
| Deposit | -50 | 600 | Rejected — negative amount |
| Withdraw | -50 | 600 | Rejected — negative amount |
| Deposit | 0 | 600 | Rejected — zero amount |
Bonus
- Add transfer between two accounts — atomic operation, both sides must succeed
- Add overdraft limit — allow withdrawals up to a configurable negative balance
- Add interest calculation — apply monthly interest based on average daily balance
- Add transaction categories — tag transactions and filter statements by category
Reference Walkthrough
Full C#, TypeScript, and Python implementations live at tddbuddy-reference-katas/bank-account with the same twenty scenarios across all three languages, a fluent AccountBuilder, and a Clock collaborator so tests don’t depend on real time.
- C# (.NET 8, xUnit, FluentAssertions) — walkthrough
- TypeScript (Node 20, Vitest, strict types) — walkthrough
- Python (3.11, pytest, dataclasses) — walkthrough
Unlike Gilded Rose (which ships in low gear, one commit per scenario), Bank Account ships in middle gear — a single commit per language with the full domain design. See the repo’s Gears section for why that’s a deliberate teaching choice.
Related reading
- Examples Pin Intent. Properties Pin the Invariants.
Example-based tests anchor scenarios in the team's vocabulary. Property-based tests anchor invariants across the input space. The agent needs both axes, and most suites only carry one. - The Test Pyramid Was an Economic Argument
The test pyramid was not a quality law. It was a cost structure: unit tests were cheap, integration tests were expensive, so you wrote many of the first and few of the second. Agents collapsed the cost of writing tests at every level, and the cheapest test that still tells the truth is the one that pins a seam the agent cannot fake. - Agents Amplify Whatever Vocabulary They Find
Agents do not bring vocabulary to your codebase. They mirror what's already there. Strong vocabulary gets agent contributions that read like the team. Weak vocabulary gets faster mediocrity. The work you did for craft reasons just became leverage.