Hoe TDD een lijstimplementatie in Java

1. Overzicht

In deze tutorial zullen we door een custom Lijst implementatie met behulp van het Test-Driven Development (TDD) -proces.

Dit is geen inleiding tot TDD, dus we gaan ervan uit dat je al een basisidee hebt van wat het betekent en de aanhoudende interesse om er beter in te worden.

Simpel gezegd, TDD is een ontwerptool waarmee we onze implementatie kunnen aansturen met behulp van tests.

Een korte disclaimer - we richten ons hier niet op het creëren van een efficiënte implementatie - maar gebruiken het alleen als een excuus om TDD-praktijken weer te geven.

2. Aan de slag

Laten we eerst het skelet voor onze klas definiëren:

openbare klasse CustomList implementeert Lijst {privé-object [] internal = {}; // lege implementatiemethoden} 

De CustomList class implementeert het Lijst interface, daarom moet het implementaties bevatten voor alle methoden die in die interface zijn gedeclareerd.

Om te beginnen kunnen we voor die methoden gewoon lege lichamen leveren. Als een methode een retourtype heeft, kunnen we een willekeurige waarde van dat type retourneren, zoals nul voor Voorwerp of false voor boolean.

Kortheidshalve laten we optionele methoden weg, samen met enkele verplichte methoden die niet vaak worden gebruikt.

3. TDD-cycli

Het ontwikkelen van onze implementatie met TDD betekent dat we dat moeten doen maak eerst testcases, waarmee we eisen stellen aan onze implementatie. Enkel en alleen dan maken of repareren we de implementatiecode om die tests te laten slagen.

Op een zeer vereenvoudigde manier zijn de drie belangrijkste stappen in elke cyclus:

  1. Schrijftesten - eisen definiëren in de vorm van tests
  2. Functies implementeren - laat de tests slagen zonder al te veel aandacht te besteden aan de elegantie van de code
  3. Refactoring - de code verbeteren om het gemakkelijker te maken om deze te lezen en te onderhouden, terwijl u toch slaagt voor de tests

We zullen deze TDD-cycli doorlopen voor enkele methoden van het Lijst interface, te beginnen met de eenvoudigste.

4. Het is leeg Methode

De is leeg methode is waarschijnlijk de meest eenvoudige methode die is gedefinieerd in de Lijst koppel. Dit is onze startimplementatie:

@Override openbare boolean isEmpty () {return false; }

Deze initiële methodedefinitie is voldoende om te compileren. De body van deze methode zal "gedwongen" worden om te verbeteren wanneer er steeds meer tests worden toegevoegd.

4.1. De eerste cyclus

Laten we de eerste testcase schrijven die ervoor zorgt dat de is leeg methode retourneert waar als de lijst geen enkel element bevat:

@Test openbare leegte gegevenEmptyList_whenIsEmpty_thenTrueIsReturned () {Lijstlijst = nieuwe CustomList (); assertTrue (list.isEmpty ()); }

De gegeven test mislukt sinds de is leeg methode keert altijd terug false. We kunnen het laten passeren door de retourwaarde om te draaien:

@Override openbare boolean isEmpty () {return true; }

4.2. De tweede cyclus

Om te bevestigen dat het is leeg methode retourneert false als de lijst niet leeg is, moeten we minstens één element toevoegen:

@Test openbare leegte gegevenNonEmptyList_whenIsEmpty_thenFalseIsReturned () {Lijstlijst = nieuwe CustomList (); list.add (null); assertFalse (lijst.isEmpty ()); }

Een implementatie van het toevoegen methode is nu vereist. Hier is de toevoegen methode beginnen we met:

@Override public boolean add (E element) {return false; }

Deze methode-implementatie werkt niet omdat er geen wijzigingen in de interne gegevensstructuur van de lijst worden aangebracht. Laten we het bijwerken om het toegevoegde element op te slaan:

@Override public boolean add (E element) {internal = new Object [] {element}; teruggeven false; }

Onze test mislukt nog steeds sinds de is leeg methode is niet verbeterd. Laten we dat doen:

@Override openbare boolean isEmpty () {if (internal.length! = 0) {return false; } else {return true; }}

De niet-lege test slaagt op dit punt.

4.3. Refactoring

Beide testcases die we tot nu toe hebben gezien, zijn geslaagd, maar de code van de is leeg methode zou eleganter kunnen zijn.

Laten we het refactoren:

@Override openbare boolean isEmpty () {return internal.length == 0; }

We kunnen zien dat tests slagen, dus de implementatie van de is leeg methode is nu voltooid.

5. Het grootte Methode

Dit is onze startende implementatie van het grootte methode waardoor de CustomList klasse om te compileren:

@Override public int size () {return 0; }

5.1. De eerste cyclus

Gebruikmakend van het bestaande toevoegen methode, kunnen we de eerste test maken voor de grootte methode, waarbij wordt gecontroleerd of de grootte van een lijst met een enkel element 1:

@Test openbare ongeldig gegevenListWithAnElement_whenSize_thenOneIsReturned () {Lijstlijst = nieuwe CustomList (); list.add (null); assertEquals (1, list.size ()); }

De test mislukt omdat het grootte methode keert terug 0. Laten we slagen met een nieuwe implementatie:

@Override public int size () {if (isEmpty ()) {return 0; } else {return internal.length; }}

5.2. Refactoring

We kunnen het grootte methode om het eleganter te maken:

@Override public int size () {return internal.length; }

De implementatie van deze methode is nu voltooid.

6. Het krijgen Methode

Hier is de startimplementatie van krijgen:

@Override public E get (int index) {return null; }

6.1. De eerste cyclus

Laten we eens kijken naar de eerste test voor deze methode, die de waarde van het enkele element in de lijst verifieert:

@Test openbare ongeldig gegevenListWithAnElement_whenGet_thenThatElementIsReturned () {Lijstlijst = nieuwe CustomList (); list.add ("baeldung"); Objectelement = lijst.get (0); assertEquals ("baeldung", element); }

De test zal slagen met deze implementatie van het krijgen methode:

@Override public E get (int index) {return (E) internal [0]; }

6.2. Verbetering

Meestal voegen we meer tests toe voordat we aanvullende verbeteringen aanbrengen in het krijgen methode. Voor die tests zijn andere methoden van de Lijst interface om de juiste beweringen te implementeren.

Deze andere methoden zijn echter nog niet volwassen genoeg, dus doorbreken we de TDD-cyclus en maken we een volledige implementatie van het krijgen methode, die in feite niet erg moeilijk is.

Dat is gemakkelijk voor te stellen krijgen moet een element uit de intern array op de opgegeven locatie met behulp van de inhoudsopgave parameter:

@Override public E get (int index) {return (E) internal [index]; }

7. Het toevoegen Methode

Dit is de toevoegen methode die we hebben gemaakt in sectie 4:

@Override public boolean add (E element) {internal = new Object [] {element}; teruggeven false; }

7.1. De eerste cyclus

Het volgende is een eenvoudige test die de geretourneerde waarde van toevoegen:

@Test openbare leegte gegevenEmptyList_whenElementIsAdded_thenGetReturnsThatElement () {Lijstlijst = nieuwe CustomList (); boolean geslaagd = list.add (null); assertTrue (geslaagd); }

We moeten het toevoegen methode om terug te keren waar om de test te halen:

@Override public boolean add (E element) {internal = new Object [] {element}; terugkeer waar; }

Hoewel de test slaagt, is het toevoegen methode dekt nog niet alle gevallen. Als we een tweede element aan de lijst toevoegen, gaat het bestaande element verloren.

7.2. De tweede cyclus

Hier is nog een test die de vereiste toevoegt dat de lijst meer dan één element mag bevatten:

@Test openbare ongeldig gegevenListWithAnElement_whenAnotherIsAdded_thenGetReturnsBoth () {Lijstlijst = nieuwe CustomList (); list.add ("baeldung"); list.add (". com"); Object element1 = lijst.get (0); Object element2 = lijst.get (1); assertEquals ("baeldung", element1); assertEquals (". com", element2); }

De test zal mislukken omdat het toevoegen methode in zijn huidige vorm staat niet toe dat meer dan één element wordt toegevoegd.

Laten we de implementatiecode wijzigen:

@Override public boolean add (E element) {Object [] temp = Arrays.copyOf (internal, internal.length + 1); temp [internal.length] = element; intern = temp; terugkeer waar; }

De implementatie is elegant genoeg, daarom hoeven we deze niet te refactoren.

8. Conclusie

Deze tutorial heeft een testgestuurd ontwikkelingsproces doorlopen om een ​​deel van een custom Lijst implementatie. Met behulp van TDD kunnen we requirements stap voor stap implementeren, terwijl we de testdekking op een zeer hoog niveau houden. Ook is de implementatie gegarandeerd testbaar, omdat deze is gemaakt om de tests te laten slagen.

Merk op dat de aangepaste klasse die in dit artikel is gemaakt, alleen wordt gebruikt voor demonstratiedoeleinden en niet mag worden toegepast in een echt project.

De volledige broncode voor deze tutorial, inclusief de test- en implementatiemethoden die kortheidshalve zijn weggelaten, is te vinden op GitHub.