Kennisbank

Testgestuurde Ontwikkeling

Wat is testgestuurde ontwikkeling?

Testgestuurde ontwikkeling (TDD) is een softwareontwikkelingsproces dat door Kent Beck is geïntroduceerd als onderdeel van de extreme programmeermethodologie. Bij TDD worden eerst unit tests geschreven voordat implementaties worden ontwikkeld.

De eisen worden vastgelegd als testgevallen. Wanneer nieuwe eisen aan de software worden toegevoegd, worden ook nieuwe testgevallen geschreven. Terwijl het systeem wordt ontwikkeld, bouwen we een groter beeld op van de eisen en vergroten we de dekking van de unit tests.

Het TDD-proces

Het door TDD aanbevolen proces is als volgt:

  1. Schrijf een falende test.
  2. Voer de tests uit, die zouden moeten falen.
  3. Schrijf de eenvoudigst mogelijke code om de nieuwe test te laten slagen.
  4. Voer de tests uit, zodat ze nu wel slagen.
  5. Refactor indien nodig, waarbij je de tests achteraf uitvoert om er zeker van te zijn dat de functionaliteit behouden blijft.
  6. Herhaal dit proces voor nieuwe eisen.

Een belangrijk punt hierbij is dat de tests eerst worden toegevoegd voordat de functionaliteit wordt ontwikkeld. Door de eenvoudigste oplossing te schrijven slaagt de test, waarna deze door refactoring kan worden verfijnd. De tests zorgen er dan voor dat eventuele refactoring geen defecten heeft geïntroduceerd.

Voordelen

Testgestuurde ontwikkeling levert meestal code van betere kwaliteit op en vermindert de kans op defecten. Het stimuleert het gebruik van kleine iteraties bij de ontwikkeling van software.

Een nuttig neveneffect is dat de tests dienen als een vorm van documentatie voor de eisen van de software.

Code ontwikkeld onder TDD kan leiden tot flexibele en uitbreidbare code. Dit komt doordat ontwikkelaars vaak moeten denken in termen van kleinere eenheden die geïsoleerd getest en geïntegreerd kunnen worden. Omdat alleen de minimale hoeveelheid code wordt toegevoegd om de tests te laten slagen, is de kans groter dat de tests zelf alle codepaden in de software bestrijken.

Indien gebruikt in combinatie met een broncontrolesysteem, kan in het geval van falende tests de code worden teruggerold naar de laatste versie met een volledige set tests die geslaagd is.

Beperkingen

Hoewel testgestuurde ontwikkeling gemakkelijk te gebruiken is bij nieuwe projecten, is het moeilijk toe te passen op bestaande of legacysystemen. Als nieuwe code wordt toegevoegd aan legacy software, dan kunnen deze nieuwe onderdelen uiteraard worden ontwikkeld met TDD, maar het toevoegen van tests aan legacy code kan moeilijk en tijdrovend zijn.

Sommige processen zijn moeilijk te testen, zoals User Interface processen of database connectiviteit.

Een groot aantal succesvolle tests kan een vals gevoel van veiligheid geven, waardoor andere activiteiten onvoldoende worden getest.

Het ontwikkelen en onderhouden van een grote hoeveelheid tests kan een tijdrovend proces zijn.

TDD implementeren met Delphi

TDD kan eenvoudig worden gerealiseerd met DUnitX, het unit testing framework dat met Delphi wordt meegeleverd. Met de in Delphi ingebouwde wizard is het eenvoudig om een DUnitX-testproject aan te maken, compleet met een testunit en enkele voorbeeldtests.

Het schrijven van een falende test kan zo eenvoudig zijn als het schrijven van een lege test die geen enkele functionaliteit aanroept:

unit Tests.VATCalculator;

interface

uses
  DUnitX.TestFramework;

type
  [TestFixture]
  TTestVATCalculator = class
  public
    [Test]
    [TestCase ('100_Pounds', '100,20')]
    procedure TestGetVATAmount(const NetAmount: Currency; const ExpectedAmount: Currency);
  end;

implementation

procedure TTestVATCalculator.TestGetVATAmount(const NetAmount: Currency; const ExpectedAmount: Currency);
begin
  var ReturnValue: Currency;
  // No implementation
  Assert.AreEqual(ExpectedAmount, ReturnValue);
end;

initialization

  TDUnitX.RegisterTestFixture(TTestVATCalculator);

end.


Als deze test wordt uitgevoerd, zal de test mislukken. Implementeer de functionaliteit voor de test met zo eenvoudig mogelijke code:

unit VAT.Calculator.Interfaces;

interface

type
  IVATCalculator = interface
    ['{1576AC66-A116-47EB-9C6A-23D4E2C21B2C}']
    function GetVAT(const NetAmount: Currency): Currency;
  end;

implementation

end.

 

unit VAT.Calculator;

interface

uses
  VAT.Calculator.Interfaces;

type
  TVATCalculator = class(TInterfacedObject, IVATCalculator)
  public
    function GetVAT(const NetAmount: Currency): Currency;
  end;

implementation

function TVATCalculator.GetVAT(const NetAmount: Currency): Currency;
begin
  Result := NetAmount * 20 / 100;
end;

end.

 

unit Tests.VATCalculator;

interface

uses
  DUnitX.TestFramework,
  VAT.Calculator.Interfaces;

type
  [TestFixture]
  TTestVATCalculator = class
  private
    FVATCalculator: IVATCalculator;
  public
    [Setup]
    procedure Setup;

    [Test]
    [TestCase ('100_Pounds', '100,20')]
    procedure TestGetVATAmount(const NetAmount: Currency; const ExpectedAmount: Currency);
  end;

implementation

uses
  VAT.Calculator;

procedure TTestVATCalculator.Setup;
begin
  FVATCalculator := TVATCalculator.Create;
end;

procedure TTestVATCalculator.TestGetVATAmount(const NetAmount: Currency; const ExpectedAmount: Currency);
var
  ReturnValue: Currency;
begin
  ReturnValue := FVATCalculator.GetVAT(NetAmount);

  Assert.AreEqual(ExpectedAmount, ReturnValue);
end;

initialization

  TDUnitX.RegisterTestFixture(TTestVATCalculator);

end.

De tests zullen nu slagen en het proces kan worden voortgezet om meer eisen toe te voegen en waar nodig te refactoren.

Conclusion

Testgestuurde ontwikkeling is een krachtig hulpmiddel om eisen vast te leggen en ervoor te zorgen dat tests tegelijk met de software worden ontwikkeld. Het wordt het best gebruikt voor nieuwe projecten of voor het toevoegen van nieuwe modules aan bestaande projecten. Hoewel het tijdrovend kan zijn, bieden de tests een waardevol mechanisme om ervoor te zorgen dat nieuwe toevoegingen aan de software geen bestaande functionaliteit breken. Het blijft een zeer nuttig instrument in de gereedschapskist van een software-ontwikkelaar.

 

Geschreven door James Goodger
Directeur, UK

Contact

Laat ons helpen jouw ambities concreet te maken.