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.