Test Driven Development
with mORMot 2
The more tests…
the better
Welcome
Arnaud Bouchez
• Open Source Founder
• mORMot 1, mORMot 2, SynPDF, dmustache
• Modern Object Pascal
Delphi and FPC - Embarcadero MVP
• Synopse Tranquil IT
https://synopse.info https://tranquil.it
Welcome
Arnaud Bouchez
• Open Source Founder
• mORMot 1, mORMot 2, SynPDF, dmustache
• Modern Object Pascal
Delphi and FPC - Embarcadero MVP
• Synopse Tranquil IT
https://synopse.info https://tranquil.it
Test Driven Design
(aka TDD)
with mORMot 2
Disclaimer
This was a last time session…
so please by nice with me 
Today’s Special
• Technical Debt
• Software Seams
• Test Driven Design
• mormot2tests
Today’s Special
• Technical Debt
• Software Seams
• Test Driven Design
• mormot2tests
Technical Debt
Technical Debt
Technical Debt
We all know or even still maintain
Delphi software older than a few decades
– Stuck with Delphi 7 / 2007
– Stuck with a single database
– Stuck with unmaintained UI component(s)
– Stuck with millions of line of code,
without any unit tests
Technical Debt
Delphi software older than a few decades
– Stuck with Delphi 7 / 2007
– Stuck with a single database
– Stuck with unmaintained UI component(s)
– Stuck with millions of line of code,
without any unit tests
Technical Debt
Legacy Systems induce a technical debt
Like a financial debt,
incurs interest payment
• Extra efforts in any future
development
• Higher maintenance costs
Technical Debt
Marco Geuze said this morning
that legacy code is not Technical Debt
Technical Debt
Marco Geuze said this morning
that legacy code is not Technical Debt
it may not be 100% debt
but it certainly has some debt
Technical Debt
Marco Geuze said this morning
that legacy code is not Technical Debt
but of course, it is working
and has domain/business knowledge
Technical Debt
Today’s Special
• Technical Debt
• Software Seams
• Test Driven Design
• mormot2tests
Software Seams
Software Seams
Software Seams
A place where
you can alter your program behavior
without editing in that place
Software Seams
Refactoring to isolate seams via interfaces
1. Know your subject
2. Identify responsibilities big picture
3. Study data structures
4. Break out huge functions
5. Break out giant classes iterative process
6. Encapsulate global references
7. Testing is everything
Software Seams
Refactoring to isolate seams via interfaces
1. Know your subject
2. Identify responsibilities big picture
3. Study data structures
4. Break out huge functions
5. Break out giant classes iterations
6. Encapsulate global references
7. Testing is everything
Software Seams
Refactoring to isolate seams via interfaces
• AI tools may help
with iterations
Software Seams
From interface comes abstraction
• SOLID principles
• SOA and (Micro)Services
• Database agnostic
• Testing/mocking
Today’s Special
• Technical Debt
• Software Seams
• Test Driven Design
• mormot2tests
Test Driven Design
Test Driven Design
Test Driven Design
Coding is an Iterative process
• Even up to the management level
(projects)
• Ensure each step won’t break any
previous step
• Testing should be part of this process
Test Driven Design
Test Driven Design (TDD)
means “iterate from tests into tests”
Test Driven Design
TDD means “let tests pass”
1. Write the test
2. Fails the test
3. Implements the feature
4. Fails the test ? Drink a coffee and go to 3.
5. Pass the test and all previous tests
6. Continue to the next feature
Test Driven Design
Test Driven Design main benefits
 Ensure we didn’t break anything
 Expect we won’t break anything
Test Driven Design
• Test Driven Design collateral benefits
• Define the types and API early
• Refine the expectations ASAP
• Document the API before implementing
• Can mock the UI before implementing
• Tests as specification
Test Driven Design
• Mocking / Stubbing
"The Art of Unit Testing“
(Osherove, Roy - 2009)
– The power of fake objects
Stubs and Mocks
Test Driven Design
• Mocking / Stubbing
"The Art of Unit Testing" (Osherove, Roy - 2009)
– Stubs are fake objects
implementing a given contract
and returning pre-arranged responses
• They just let the test pass
• They “emulate” some behavior
(e.g. a database)
Test Driven Design
• Mocking / Stubbing
"The Art of Unit Testing" (Osherove, Roy - 2009)
– Mocks are fake objects like stubs
which will verify if an interaction occurred
or not
• They help decide if a test failed or passed
• There should be only one mock per test
Mocks and
Stubs
Test Driven Design
TLoginController = class(TInterfacedObject, ILoginController)
protected
fUserRepository: IUserRepository;
fSmsSender: ISmsSender;
public
constructor Create(const aUserRepository: IUserRepository;
const aSmsSender: ISmsSender);
procedure ForgotMyPassword(const UserName: RawUtf8);
end;
constructor TLoginController.Create(const aUserRepository: IUserRepository; const
aSmsSender: ISmsSender);
begin // dependencies injection in constructor
fUserRepository := aUserRepository;
fSmsSender := aSmsSender;
end;
Test Driven Design
IUserRepository = interface(IInvokable)
['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}']
function GetUserByName(const Name: RawUtf8): TUser;
procedure Save(const User: TUser);
end;
ISmsSender = interface(IInvokable)
['{8F87CB56-5E2F-437E-B2E6-B3020835DC61}']
function Send(const Text, Number: RawUtf8): boolean;
end;
Test Driven Design
procedure TLoginController.ForgotMyPassword(
const UserName: RawUtf8);
var U: TUser;
begin
U := fUserRepository.GetUserByName(UserName);
U.Password := Int32ToUtf8(Random31);
if fSmsSender.Send('Your new password is ' +
U.Password, U.MobilePhoneNumber) then
fUserRepository.Save(U);
end;
Expect – Run – Verify pattern
procedure TMyTest.ForgotMyPassword;
var sms: ISmsSender;
repo: IUserRepository;
begin
TInterfaceStub.Create(ISmsSender, sms).
Returns('Send', [true]);
TInterfaceMock.Create(IUserRepository, repo, self).
ExpectsCount('Save', qoEqualTo, 1);
with TLoginController.Create(repo, sms) do
try
ForgotMyPassword('toto');
finally
Free;
end;
Run – Verify (aka “Test spy”)
procedure TMyTest.ForgotMyPassword;
var sms: ISmsSender;
repo: IUserRepository;
spy: TInterfaceMockSpy;
begin
TInterfaceStub.Create(ISmsSender, sms).Returns('Send', [true]);
spy := TInterfaceMockSpy.Create(IUserRepository, repo, self);
with TLoginController.Create(repo, sms) do
try
ForgotMyPassword('toto');
finally
Free;
end;
spy.Verify('Save');
Test Driven Design
Mocking / Stubbing - another features
• Return complex values (e.g. a DTO)
• Use a delegate to create a stub/mock
• Using named or indexed variant parameters
• Using JSON array of values
Test Driven Design
Mocking / Stubbing - another features
• Access the test case when mocking
• Trace and verify the calls
• With a fluent interface
• Log all calls (as JSON)
Today’s Special
• Technical Debt
• Software Seams
• Test Driven Design
• mormot2tests
mormot2tests
mormot2tests
mormot2tests
Where I spend most of my time:
 Write a new feature test
 Implement the feature
 Debug to let it pass
 Run all other tests
mormot2tests
Console application
• Part of mORMot repository
• Delphi and FPC
• On all supported systems (LUTI)
mormot2tests
Several kind of tests
 Unitary tests
 Integration tests
 Stability tests (threads, OS…)
 Performance tests
mormot2tests
“LUTI” nightly integration tests
https://luti.tranquil.it/listfolder/b469
db22-f483-45c2-90a8-
f640c1eb8457
mormot2tests
SHOW ME THE CODE !
To Visit the marmots
https://cauterets.site
Questions?

Test Driven Development with mORMot 2 with Delphi and FPC

  • 1.
    Test Driven Development withmORMot 2 The more tests… the better
  • 2.
    Welcome Arnaud Bouchez • OpenSource Founder • mORMot 1, mORMot 2, SynPDF, dmustache • Modern Object Pascal Delphi and FPC - Embarcadero MVP • Synopse Tranquil IT https://synopse.info https://tranquil.it
  • 3.
    Welcome Arnaud Bouchez • OpenSource Founder • mORMot 1, mORMot 2, SynPDF, dmustache • Modern Object Pascal Delphi and FPC - Embarcadero MVP • Synopse Tranquil IT https://synopse.info https://tranquil.it
  • 4.
    Test Driven Design (akaTDD) with mORMot 2
  • 5.
    Disclaimer This was alast time session… so please by nice with me 
  • 6.
    Today’s Special • TechnicalDebt • Software Seams • Test Driven Design • mormot2tests
  • 7.
    Today’s Special • TechnicalDebt • Software Seams • Test Driven Design • mormot2tests
  • 8.
  • 9.
  • 10.
    Technical Debt We allknow or even still maintain Delphi software older than a few decades – Stuck with Delphi 7 / 2007 – Stuck with a single database – Stuck with unmaintained UI component(s) – Stuck with millions of line of code, without any unit tests
  • 11.
    Technical Debt Delphi softwareolder than a few decades – Stuck with Delphi 7 / 2007 – Stuck with a single database – Stuck with unmaintained UI component(s) – Stuck with millions of line of code, without any unit tests
  • 12.
    Technical Debt Legacy Systemsinduce a technical debt Like a financial debt, incurs interest payment • Extra efforts in any future development • Higher maintenance costs
  • 13.
    Technical Debt Marco Geuzesaid this morning that legacy code is not Technical Debt
  • 14.
    Technical Debt Marco Geuzesaid this morning that legacy code is not Technical Debt it may not be 100% debt but it certainly has some debt
  • 15.
    Technical Debt Marco Geuzesaid this morning that legacy code is not Technical Debt but of course, it is working and has domain/business knowledge
  • 16.
  • 17.
    Today’s Special • TechnicalDebt • Software Seams • Test Driven Design • mormot2tests
  • 18.
  • 19.
  • 20.
    Software Seams A placewhere you can alter your program behavior without editing in that place
  • 21.
    Software Seams Refactoring toisolate seams via interfaces 1. Know your subject 2. Identify responsibilities big picture 3. Study data structures 4. Break out huge functions 5. Break out giant classes iterative process 6. Encapsulate global references 7. Testing is everything
  • 22.
    Software Seams Refactoring toisolate seams via interfaces 1. Know your subject 2. Identify responsibilities big picture 3. Study data structures 4. Break out huge functions 5. Break out giant classes iterations 6. Encapsulate global references 7. Testing is everything
  • 23.
    Software Seams Refactoring toisolate seams via interfaces • AI tools may help with iterations
  • 24.
    Software Seams From interfacecomes abstraction • SOLID principles • SOA and (Micro)Services • Database agnostic • Testing/mocking
  • 25.
    Today’s Special • TechnicalDebt • Software Seams • Test Driven Design • mormot2tests
  • 26.
  • 27.
  • 28.
    Test Driven Design Codingis an Iterative process • Even up to the management level (projects) • Ensure each step won’t break any previous step • Testing should be part of this process
  • 29.
    Test Driven Design TestDriven Design (TDD) means “iterate from tests into tests”
  • 30.
    Test Driven Design TDDmeans “let tests pass” 1. Write the test 2. Fails the test 3. Implements the feature 4. Fails the test ? Drink a coffee and go to 3. 5. Pass the test and all previous tests 6. Continue to the next feature
  • 31.
    Test Driven Design TestDriven Design main benefits  Ensure we didn’t break anything  Expect we won’t break anything
  • 32.
    Test Driven Design •Test Driven Design collateral benefits • Define the types and API early • Refine the expectations ASAP • Document the API before implementing • Can mock the UI before implementing • Tests as specification
  • 33.
    Test Driven Design •Mocking / Stubbing "The Art of Unit Testing“ (Osherove, Roy - 2009) – The power of fake objects Stubs and Mocks
  • 34.
    Test Driven Design •Mocking / Stubbing "The Art of Unit Testing" (Osherove, Roy - 2009) – Stubs are fake objects implementing a given contract and returning pre-arranged responses • They just let the test pass • They “emulate” some behavior (e.g. a database)
  • 35.
    Test Driven Design •Mocking / Stubbing "The Art of Unit Testing" (Osherove, Roy - 2009) – Mocks are fake objects like stubs which will verify if an interaction occurred or not • They help decide if a test failed or passed • There should be only one mock per test
  • 36.
  • 37.
    Test Driven Design TLoginController= class(TInterfacedObject, ILoginController) protected fUserRepository: IUserRepository; fSmsSender: ISmsSender; public constructor Create(const aUserRepository: IUserRepository; const aSmsSender: ISmsSender); procedure ForgotMyPassword(const UserName: RawUtf8); end; constructor TLoginController.Create(const aUserRepository: IUserRepository; const aSmsSender: ISmsSender); begin // dependencies injection in constructor fUserRepository := aUserRepository; fSmsSender := aSmsSender; end;
  • 38.
    Test Driven Design IUserRepository= interface(IInvokable) ['{B21E5B21-28F4-4874-8446-BD0B06DAA07F}'] function GetUserByName(const Name: RawUtf8): TUser; procedure Save(const User: TUser); end; ISmsSender = interface(IInvokable) ['{8F87CB56-5E2F-437E-B2E6-B3020835DC61}'] function Send(const Text, Number: RawUtf8): boolean; end;
  • 39.
    Test Driven Design procedureTLoginController.ForgotMyPassword( const UserName: RawUtf8); var U: TUser; begin U := fUserRepository.GetUserByName(UserName); U.Password := Int32ToUtf8(Random31); if fSmsSender.Send('Your new password is ' + U.Password, U.MobilePhoneNumber) then fUserRepository.Save(U); end;
  • 40.
    Expect – Run– Verify pattern procedure TMyTest.ForgotMyPassword; var sms: ISmsSender; repo: IUserRepository; begin TInterfaceStub.Create(ISmsSender, sms). Returns('Send', [true]); TInterfaceMock.Create(IUserRepository, repo, self). ExpectsCount('Save', qoEqualTo, 1); with TLoginController.Create(repo, sms) do try ForgotMyPassword('toto'); finally Free; end;
  • 41.
    Run – Verify(aka “Test spy”) procedure TMyTest.ForgotMyPassword; var sms: ISmsSender; repo: IUserRepository; spy: TInterfaceMockSpy; begin TInterfaceStub.Create(ISmsSender, sms).Returns('Send', [true]); spy := TInterfaceMockSpy.Create(IUserRepository, repo, self); with TLoginController.Create(repo, sms) do try ForgotMyPassword('toto'); finally Free; end; spy.Verify('Save');
  • 42.
    Test Driven Design Mocking/ Stubbing - another features • Return complex values (e.g. a DTO) • Use a delegate to create a stub/mock • Using named or indexed variant parameters • Using JSON array of values
  • 43.
    Test Driven Design Mocking/ Stubbing - another features • Access the test case when mocking • Trace and verify the calls • With a fluent interface • Log all calls (as JSON)
  • 44.
    Today’s Special • TechnicalDebt • Software Seams • Test Driven Design • mormot2tests
  • 45.
  • 46.
  • 47.
    mormot2tests Where I spendmost of my time:  Write a new feature test  Implement the feature  Debug to let it pass  Run all other tests
  • 48.
    mormot2tests Console application • Partof mORMot repository • Delphi and FPC • On all supported systems (LUTI)
  • 49.
    mormot2tests Several kind oftests  Unitary tests  Integration tests  Stability tests (threads, OS…)  Performance tests
  • 50.
    mormot2tests “LUTI” nightly integrationtests https://luti.tranquil.it/listfolder/b469 db22-f483-45c2-90a8- f640c1eb8457
  • 51.
  • 52.
    To Visit themarmots https://cauterets.site
  • 53.