agentsclimarketplace

Dunitx testing

Skill delphicleancode/delphi-spec-kit/.gemini/skills/dunitx-testing

An opinionated ecosystem of rules, skills, and steerings to elevate Delphi development to a state-of-the-art level with Artificial Intelligence.

Install
npx -y skills add delphicleancode/delphi-spec-kit --skill dunitx-testing

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Unit testing patterns with DUnitX for Delphi — fixtures, mocking, integration tests

SKILL.md

6.8 KB, as published. Nobody here has run it

DUnitX Testing Patterns — Skill

Use this skill when creating or organizing unit tests in Delphi projects.

When to Use

  • When creating tests for new features
  • When applying TDD (Test-Driven Development)
  • When creating database integration tests
  • When refactoring existing tests

Test Project Structure

tests/
├── MeuApp.Tests.dpr                 ← Projeto de testes
├── Domain/
│   ├── MeuApp.Tests.Customer.Entity.pas
│   └── MeuApp.Tests.Order.Entity.pas
├── Application/
│   ├── MeuApp.Tests.Customer.Service.pas
│   └── MeuApp.Tests.Order.Service.pas
├── Infrastructure/
│   └── MeuApp.Tests.Customer.Repository.pas
└── Helpers/
    ├── MeuApp.Tests.Helpers.Database.pas
    └── MeuApp.Tests.Helpers.Mocks.pas

Basic Test Fixture

unit MeuApp.Tests.Customer.Service;

interface

uses
  DUnitX.TestFramework,
  MeuApp.Domain.Customer.Entity,
  MeuApp.Domain.Customer.Repository.Intf,
  MeuApp.Application.Customer.Service;

type
  [TestFixture]
  TCustomerServiceTest = class
  private
    FService: TCustomerService;
    FMockRepo: ICustomerRepository;
  public
    [Setup]
    procedure Setup;

    [TearDown]
    procedure TearDown;

    [Test]
    procedure CreateCustomer_WithValidData_ShouldSucceed;

    [Test]
    procedure CreateCustomer_WithEmptyName_ShouldRaiseException;

    [Test]
    procedure CreateCustomer_WithDuplicateCpf_ShouldRaiseException;

    [Test]
    procedure GetById_WithExistingId_ShouldReturnCustomer;

    [Test]
    procedure GetById_WithInvalidId_ShouldRaiseNotFoundException;
  end;

implementation

uses
  System.SysUtils;

{ TCustomerServiceTest }

procedure TCustomerServiceTest.Setup;
begin
  FMockRepo := TMemoryCustomerRepository.Create;
  FService := TCustomerService.Create(FMockRepo);
end;

procedure TCustomerServiceTest.TearDown;
begin
  FService.Free;
  // FMockRepo é interface — liberado automaticamente
end;

[Test]
procedure TCustomerServiceTest.CreateCustomer_WithValidData_ShouldSucceed;
begin
  Assert.WillNotRaiseAny(
    procedure
    begin
      FService.CreateCustomer('João Silva', '12345678901', '[email protected]');
    end
  );
end;

[Test]
procedure TCustomerServiceTest.CreateCustomer_WithEmptyName_ShouldRaiseException;
begin
  Assert.WillRaise(
    procedure
    begin
      FService.CreateCustomer('', '12345678901', '[email protected]');
    end,
    EValidationException
  );
end;

[Test]
procedure TCustomerServiceTest.CreateCustomer_WithDuplicateCpf_ShouldRaiseException;
begin
  FService.CreateCustomer('João', '12345678901', '[email protected]');

  Assert.WillRaise(
    procedure
    begin
      FService.CreateCustomer('Maria', '12345678901', '[email protected]');
    end,
    EBusinessRuleException
  );
end;

[Test]
procedure TCustomerServiceTest.GetById_WithExistingId_ShouldReturnCustomer;
var
  LCustomer: TCustomer;
begin
  FService.CreateCustomer('João', '12345678901', '[email protected]');

  LCustomer := FService.GetById(1);
  try
    Assert.IsNotNull(LCustomer);
    Assert.AreEqual('João', LCustomer.Name);
  finally
    LCustomer.Free;
  end;
end;

[Test]
procedure TCustomerServiceTest.GetById_WithInvalidId_ShouldRaiseNotFoundException;
begin
  Assert.WillRaise(
    procedure
    begin
      FService.GetById(999);
    end,
    EEntityNotFoundException
  );
end;

initialization
  TDUnitX.RegisterTestFixture(TCustomerServiceTest);

end.

Mock Repository (in memory)

unit MeuApp.Tests.Helpers.Mocks;

interface

uses
  System.SysUtils,
  System.Generics.Collections,
  MeuApp.Domain.Customer.Entity,
  MeuApp.Domain.Customer.Repository.Intf;

type
  TMemoryCustomerRepository = class(TInterfacedObject, ICustomerRepository)
  private
    FItems: TObjectList<TCustomer>;
    FNextId: Integer;
  public
    constructor Create;
    destructor Destroy; override;

    function FindById(AId: Integer): TCustomer;
    function FindAll: TObjectList<TCustomer>;
    function FindByCpf(const ACpf: string): TCustomer;
    function Exists(AId: Integer): Boolean;
    procedure Insert(ACustomer: TCustomer);
    procedure Update(ACustomer: TCustomer);
    procedure Delete(AId: Integer);
  end;

implementation

constructor TMemoryCustomerRepository.Create;
begin
  inherited Create;
  FItems := TObjectList<TCustomer>.Create(False);
  FNextId := 1;
end;

destructor TMemoryCustomerRepository.Destroy;
begin
  FItems.Free;
  inherited;
end;

procedure TMemoryCustomerRepository.Insert(ACustomer: TCustomer);
begin
  ACustomer.Id := FNextId;
  Inc(FNextId);
  FItems.Add(ACustomer);
end;

// ... demais métodos seguem o mesmo default

Test Naming Conventions

MethodName_Scenario_ExpectedBehavior
ExampleMeaning
CreateCustomer_WithValidData_ShouldSucceedHappy scenery
CreateCustomer_WithEmptyName_ShouldRaiseExceptionValidation
GetById_WithInvalidId_ShouldRaiseNotFoundExceptionNot found
Delete_WhenItemHasDependencies_ShouldRaiseExceptionBusiness rule

DUnitX Common Assertions

// Igualdade
Assert.AreEqual(Expected, Actual);
Assert.AreEqual('João', LCustomer.Name);

// Nulidade
Assert.IsNotNull(LCustomer);
Assert.IsNull(LResult);

// Booleanos
Assert.IsTrue(LCustomer.IsActive);
Assert.IsFalse(LOrder.IsCancelled);

// Exceptions
Assert.WillRaise(AnonProc, EValidationException);
Assert.WillNotRaiseAny(AnonProc);

// Contagem
Assert.AreEqual(3, LList.Count);

Integration Test with SQLite in Memory

[TestFixture]
TCustomerRepositoryIntegrationTest = class
private
  FConnection: TFDConnection;
  FRepository: ICustomerRepository;
public
  [Setup]
  procedure Setup;

  [TearDown]
  procedure TearDown;
end;

procedure TCustomerRepositoryIntegrationTest.Setup;
begin
  FConnection := TFDConnection.Create(nil);
  FConnection.DriverName := 'SQLite';
  FConnection.Params.Database := ':memory:';
  FConnection.Connected := True;

  // Criar schema
  FConnection.ExecSQL(
    'CREATE TABLE customers (' +
    '  id INTEGER PRIMARY KEY AUTOINCREMENT,' +
    '  name TEXT NOT NULL,' +
    '  cpf TEXT NOT NULL,' +
    '  email TEXT,' +
    '  status INTEGER DEFAULT 0' +
    ')'
  );

  FRepository := TFireDACCustomerRepository.Create(FConnection);
end;

procedure TCustomerRepositoryIntegrationTest.TearDown;
begin
  FConnection.Free;
end;

Test Checklist

  • Test name follows MethodName_Scenario_ExpectedBehavior?
  • Clean setup and TearDown without side effects?
  • Test checks ONE thing?
  • Objects released correctly in TearDown and in try/finally?
  • Mock repository used for Service testing?
  • SQLite :memory: used for Repository integration testing?
  • Test happy scenario AND error scenarios?

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.