Home

Course

Learn Java with Tests

A test-driven development course for Java, inspired by Learn Go with Tests. Every chapter is a tiny, self-contained package: read the failing test, implement the minimum to make it pass, refactor.

Start here — clone the blank template

This course is a do, not a read. Clone the blank starter project — Gradle, JUnit 5 and AssertJ are already wired — and you build each chapter's package yourself:

git clone https://github.com/gdguesser/learn-java-with-tests-starter.git
cd learn-java-with-tests-starter
./gradlew test                     # toolchain ready, no tests yet

./gradlew test is the loop that drives every chapter; on Windows use gradlew.bat test. Then open chapter 01 and create src/main/java/hello and src/test/java/hello yourself — your first failing run (a "cannot find symbol" compile error) will be your first RED.

The solutions repo contains all 18 chapters written and tested — compare against it once a chapter is green. Full setup walkthrough (JDK install, editors, troubleshooting): Getting started.

1

Write a failing test

Describe one piece of behaviour as a test before any production code exists.

2

Make it pass

Write the minimum code to satisfy the test — no more than that.

3

Refactor

Clean up the code while the green tests keep you safe. Repeat.

Chapters

  1. 01Hello, worldYour first JUnit test, assertEquals, and the RED-GREEN-REFACTOR loop.
  2. 02IntegersassertEquals on primitives and parameterized tests with @CsvSource.
  3. 03IterationLoops, StringBuilder, and refactoring to String.repeat.
  4. 04ListsList.of, enhanced for-loops, and your first streams refactor.
  5. 05Structs (records)Records as immutable data with behaviour, and float comparisons with a delta.
  6. 06InterfacesPolymorphism behind a Shape contract, tested through the interface.
  7. 07MapsWord counting with Map, merge, and a streams groupingBy refactor.
  8. 08Streamsfilter, map, and reduce — the functional way to process collections.
  9. 09OptionalsDesigning absence with Optional instead of null.
  10. 10ExceptionsassertThrows, assertAll, and exceptions as part of the contract.
  11. 11Dependency injectionConstructor injection, @FunctionalInterface, and the composition root.
  12. 12MockingHand-rolled fakes and spies — test the choreography, not the wait.
  13. 13ConcurrencyExecutorService, CompletableFuture, and virtual threads — submit everything, then join.
  14. 14Select & timeoutsCompletableFuture.anyOf to race tasks, plus timeouts that fail loudly.
  15. 15SynchronizationData races, synchronized, LongAdder, and ConcurrentHashMap — correctness by construction.
  16. 16ReflectionClass, Field, and Method — the machinery behind frameworks you almost never need yourself.
  17. 17Real project: an HTTP serverThe JDK's HttpServer and HttpClient — I/O at the edge, decisions in a testable core.
  18. 18AssertJFluent assertions that read like sentences and fail with useful diffs.