Delphi Test-Driven Development (TDD) and DUnitX

SkillDev tools

Guidelines on how the AI ​​should act and code when the user requests TDD, unit tests, DUnitX or fakes/mocks using Interfaces in Delphi.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Delphi Test-Driven Development (TDD) and DUnitX skill

What this skill tells your AI

The instructions your AI receives, as published by delphicleancode/delphi-spec-kit in .claude/skills/tdd-dunitx/SKILL.md and read by ahel’s review.

This skill guides behavioral expectations for test-driven development (TDD) using the modern Delphi ecosystem.

When operating under the scope of TDD, AI MUST ALWAYS prioritize the Red-Green-Refactor cycle. If the user requests TDD, DO NOT write the business implementation before writing the test that will fail.

The Red-Green-Refactor Cycle (Interaction Rules)

  1. Red (Failed Test): Start by declaring the skeleton of the target class/interface in the interface section just to compile. Then, immediately write a complete DUnitX Test Case calling out the non-existent behavior or asserting an expected result. The test will logically fail.
  2. Green (Minimal Code): Write the minimum and raw actual implementation, enough to make the test Assert pass.
  3. Refactor (Cleaning): Improve the code (Clean Code, duplication removal, optimizations) ensuring that the test does not break.

DUnitX Best Practices

Test Structure

  • Test Class: The test case must be annotated with [TestFixture].
  • Setup and TearDown: Use [Setup] to instantiate Classes and Fakes. Use [TearDown] to clean up instances that do not use ARC (Interfaces).
  • No Memory Leaks in Tests: [TearDown] and injection via Interface (ARC) are mandatory to keep the suite watertight.

Nomenclature of Test Methods

Embrace context conventions like Action_Condition_ExpectedResult:

[Test]
procedure ComputeDiscount_LoyalCustomer_ReturnsTenPercent;

Modern Assertions

Replace manual Boolean validations (Assert.IsTrue(A = B)) with fluent and specific Assert:

  • Assert.AreEqual(100.0, FInvoice.Total)
  • Assert.IsNotNull(FCustomer)
  • Assert.WillRaise(procedure begin FSut.DoInvalid; end, EBusinessRuleException)
  • Assert.Contains('Error', LMessage)

Dependency Injection and Mocks (Test Doubles)

To isolate the class under test (SUT - System Under Test) from the infrastructure (Database, APIs, View), apply Strict Dependency Inversion (DIP) by injecting Interfaces into the SUT via constructor.

As Delphi does not have a built-in Mocking Framework in RTL, write local "Fake/Mock" Classes implementing the Interface to simulate the dependency within the test's implementation session.

//Fake is created only in the test file
TFakeEmailService = class(TInterfacedObject, IEmailService)
public
  SentCount: Integer;
  procedure Send(const AMsg: string);
end;

AntiPatterns that AI should Avoid

  1. ❌ Direct coupling to the database (TFDQuery) in the tested class. Always abstract database access into a IRepository and create a TFakeRepository for DUnitX.
  2. ❌ Test UI. Restrict the scope of DUnitX to the Domain and Application Services Layer.
  3. ❌ Write the entire class along with the tests. The user must be followed step-by-step in TDD. If the AI ​​is required to provide everything, send the Tests first in the output.
  4. ❌ Swallowing Exceptions (try..except on E: Exception do) in methods being tested, this breaks Assert.WillRaise().

Signals

GitHub stars
50
Forks
14
Last commit
Mar 2026
Advanced
Catalog kind
skill
Gateway key
delphi-test-driven-development-tdd-and-dunitx
Source
github.com/delphicleancode/delphi-spec-kit