4D Training & Consultancy

Software Development

Java Testing and TDD with JUnit 5

A working course on Java testing for teams whose suite is slow, brittle, or quietly ignored. Participants write tests with JUnit 5, isolate collaborators with Mockito, exercise real dependencies through Testcontainers, and practise the test-driven cycle on features that resemble their own backlog.

3 daysIn-house, online, or customized deliveryCorporate teams and professional groupsLevel: Intermediate

Overview

Practical learning for workplace transfer.

A test suite fails a team in one of two ways: it breaks whenever code is refactored, or it stays green while defects reach customers. Both come from asserting implementation details instead of behaviour, and both end the same way, with a team that skips the suite to make a deadline. This course rebuilds the discipline of deciding what to assert, what to isolate, and what to leave real, using JUnit 5 capabilities most teams never adopt: parameterized and nested tests, lifecycle control, grouped assertions, and tagged execution. Participants practise red-green-refactor on new work and learn how to introduce tests around code written without any.

Prerequisites

Practical Java development experience and familiarity with Maven or Gradle. No prior JUnit 5 experience is required.

Objectives

  • Write expressive JUnit 5 tests using parameterized, nested, and tagged structures.
  • Distinguish stubs, mocks, fakes, and spies, and use Mockito without over-specifying behaviour.
  • Test data access and messaging against real dependencies using Testcontainers.
  • Practise the red-green-refactor cycle on both new features and defect fixes.
  • Design tests that assert behaviour so refactoring improves code without breaking the suite.
  • Set coverage, execution time, and flakiness targets a build pipeline can enforce.

Target audience

  • Java developers accountable for the tests that ship with their code
  • Test automation engineers working inside Java codebases
  • Technical leads raising the quality bar on an inherited test suite
  • QA engineers moving from manual checks to code-level tests
  • Teams introducing continuous integration for a Java product
  • Developers maintaining modules with little or no existing coverage

Program outline

A clear structure for the learning journey.

Program outline

Outline points are grouped in one designed block instead of being treated as separate module cards.

Module 1: What to Test, and Why Suites Rot

Separating the responsibilities of unit, integration, and end-to-end tests

Behaviour versus implementation, and why the difference decides suite lifespan

Naming and arrangement that let a test read as a specification

The economics of a slow suite and the moment teams start bypassing it

Module 2: JUnit 5 in Depth

The Jupiter lifecycle, extensions, and the migration path from JUnit 4

Parameterized tests driven by value, CSV, enum, and method sources

Nested tests, display names, and assumptions for conditional execution

Grouped assertions, exception assertions, timeouts, and tag-based selection

Module 3: Test Doubles and Mockito

Stubs, mocks, fakes, and spies: choosing the weakest double that works

Mockito stubbing, argument matchers, and verification without over-specifying

Designing for testability through injection, pure functions, and small seams

Mocking boundaries you own, and never mocking types you do not control

Module 4: Integration Testing with Testcontainers

Running databases, brokers, and dependencies as disposable containers

Spring Boot test slices weighed against full application context tests

Deterministic test data, isolation between tests, and a cleanup strategy

Keeping integration tests fast enough to run on every commit

Module 5: Test-Driven Development in Practice

Applying red-green-refactor to a feature with real acceptance criteria

Letting tests drive a design without freezing the implementation too early

Reproducing a reported defect as a failing test before repairing it

Where TDD pays, where it slows delivery, and how to make that call

Module 6: Legacy Code, Coverage, and the Pipeline

Characterization tests that pin existing behaviour before it is changed

Finding seams and refactoring safely to make untestable code testable

Reading coverage honestly: what the number does and does not prove

Flaky test triage, execution time budgets, and continuous integration gates

Materials provided

  • Course workbook, annotated code samples, and reference notes
  • Hands-on lab environment and starter repositories
  • Exercises, checklists, and reusable code templates
  • 4D Certificate of Completion
  • Post-course technical guidance

Training Options

Programs can be delivered in-house, online, or in a blended format depending on your team's schedule, location, and learning objectives. When an external certificate or exam is included, certification rules and fees remain under the relevant awarding body's policies, while 4D provides the training and preparation support.

Why choose 4D

4D runs this course against a codebase carrying the same testing problems as yours: legacy classes without seams, mocks that assert far too much, and integration tests too slow to run on a commit. Participants leave with a written suite policy covering execution time, flaky test handling, and pipeline gates the team agreed rather than inherited.

Speak to 4D

Plan the right training or consultancy path for your team.

Share a few details and 4D will help route your inquiry toward corporate training, consultancy, assessment, Phoenix-enabled support, or a tailored program.