Sådan TDD en listeimplementering i Java

1. Oversigt

I denne vejledning gennemgår vi en brugerdefineret Liste implementering ved hjælp af TDD-processen (Test-Driven Development).

Dette er ikke en introduktion til TDD, så vi antager, at du allerede har en grundlæggende idé om, hvad det betyder, og den vedvarende interesse for at blive bedre til det.

Kort fortalt, TDD er et designværktøj, der gør det muligt for os at køre vores implementering ved hjælp af test.

En hurtig ansvarsfraskrivelse - vi fokuserer ikke på at skabe effektiv implementering her - bare ved at bruge det som en undskyldning for at vise TDD-praksis.

2. Kom godt i gang

Lad os først definere skelet til vores klasse:

offentlig klasse CustomList implementerer Liste {privat Objekt [] intern = {}; // tomme implementeringsmetoder} 

Det CustomList klasse implementerer Liste interface, derfor skal den indeholde implementeringer for alle de metoder, der er angivet i denne grænseflade.

For at komme i gang kan vi bare levere tomme kroppe til disse metoder. Hvis en metode har en returtype, kan vi returnere en vilkårlig værdi af den type, f.eks nul til Objekt eller falsk til boolsk.

Af kortheds skyld vil vi udelade valgfri metoder sammen med nogle obligatoriske metoder, der ikke ofte bruges.

3. TDD-cykler

At udvikle vores implementering med TDD betyder, at vi har brug for det lav først testsagerog derved definerer krav til vores implementering. Kun så opretter eller retter vi implementeringskoden for at få disse prøver bestået.

På en meget forenklet måde er de tre hovedtrin i hver cyklus:

  1. Skriveprøver - definere krav i form af test
  2. Implementeringsfunktioner - få testene til at bestå uden at fokusere for meget på kodens elegance
  3. Refactoring - forbedre koden for at gøre det lettere at læse og vedligeholde, mens du stadig består testene

Vi gennemgår disse TDD-cyklusser for nogle metoder til Liste interface, startende med de enkleste.

4. Den er tom Metode

Det er tom metoden er sandsynligvis den mest ligefremme metode, der er defineret i Liste interface. Her er vores startimplementering:

@ Override offentlig boolsk isEmpty () {returner falsk; }

Denne indledende metodedefinition er nok til at kompilere. Selve metoden til denne metode vil blive "tvunget" til at forbedre, når flere og flere tests tilføjes.

4.1. Den første cyklus

Lad os skrive den første testsag, der sørger for, at er tom metoden vender tilbage rigtigt når listen ikke indeholder noget element:

@Test offentlig ugyldighed givenEmptyList_whenIsEmpty_thenTrueIsReturned () {List list = new CustomList (); assertTrue (list.isEmpty ()); }

Den givne test mislykkes, siden er tom metoden vender altid tilbage falsk. Vi kan få det til at passere bare ved at vende returværdien:

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

4.2. Anden cyklus

For at bekræfte, at er tom metoden vender tilbage falsk når listen ikke er tom, skal vi tilføje mindst et element:

@Test offentlig ugyldighed givenNonEmptyList_whenIsEmpty_thenFalseIsReturned () {List list = new CustomList (); list.add (null); assertFalse (list.isEmpty ()); }

En implementering af tilføje metoden er nu påkrævet. Her er den tilføje metode, vi starter med:

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

Denne metodeimplementering fungerer ikke, da der ikke foretages ændringer i listen interne datastruktur. Lad os opdatere det for at gemme det tilføjede element:

@ Override offentlig boolsk tilføjelse (E-element) {intern = nyt objekt [] {element}; returner falsk; }

Vores test mislykkes stadig siden er tom metoden er ikke blevet forbedret. Lad os gøre det:

@Override public boolean isEmpty () {if (internal.length! = 0) {return false; } andet {returner sandt; }}

Den ikke-tomme test består på dette tidspunkt.

4.3. Refactoring

Begge testsager, vi hidtil har set, passerer, men koden til er tom metoden kunne være mere elegant.

Lad os reflektere det:

@ Override offentlig boolsk isEmpty () {returner intern. Længde == 0; }

Vi kan se, at testene bestå, så implementeringen af er tom metoden er færdig nu.

5. Den størrelse Metode

Dette er vores start implementering af størrelse metode, der muliggør CustomList klasse at sammensætte:

@Override public int størrelse () {return 0; }

5.1. Den første cyklus

Brug af det eksisterende tilføje metode, kan vi oprette den første test til størrelse metode, der bekræfter, at størrelsen på en liste med et enkelt element er 1:

@Test offentlig ugyldighed givenListWithAnElement_whenSize_thenOneIsReturned () {List list = new CustomList (); list.add (null); assertEquals (1, list.size ()); }

Testen mislykkes, da størrelse metoden vender tilbage 0. Lad os få det til at passere med en ny implementering:

@Override public int size () {if (isEmpty ()) {return 0; } ellers {returner intern.længde; }}

5.2. Refactoring

Vi kan refaktorere størrelse metode til at gøre det mere elegant:

@ Override public int-størrelse () {returner intern.længde; }

Implementeringen af ​​denne metode er nu afsluttet.

6. Den Metode

Her er den igangværende implementering af :

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

6.1. Den første cyklus

Lad os tage et kig på den første test for denne metode, som verificerer værdien af ​​det enkelte element på listen:

@Test offentlig ugyldighed givenListWithAnElement_whenGet_thenThatElementIsReturned () {List list = new CustomList (); list.add ("baeldung"); Objektelement = list.get (0); assertEquals ("baeldung", element); }

Testen vil bestå med denne implementering af metode:

@ Override offentlig E get (int index) {return (E) intern [0]; }

6.2. Forbedring

Normalt vil vi tilføje flere tests, før vi foretager yderligere forbedringer af metode. Disse tests ville have brug for andre metoder til Liste interface til at implementere korrekte påstande.

Disse andre metoder er dog ikke modne nok endnu, så vi bryder TDD-cyklussen og skaber en komplet implementering af metode, som faktisk ikke er meget hård.

Det er let at forestille sig det skal udtrække et element fra indre array på det angivne sted ved hjælp af indeks parameter:

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

7. Den tilføje Metode

Dette er tilføje metode, vi oprettede i afsnit 4:

@ Override offentlig boolsk tilføjelse (E-element) {intern = nyt objekt [] {element}; returner falsk; }

7.1. Den første cyklus

Følgende er en simpel test, der verificerer returværdien af tilføje:

@Test offentlig ugyldighed givenEmptyList_whenElementIsAdded_thenGetReturnsThatElement () {List list = new CustomList (); boolsk lykkedes = list.add (null); assertTrue (lykkedes); }

Vi skal ændre tilføje metode til at vende tilbage rigtigt for at testen skal bestå:

@ Override offentlig boolsk tilføj (E-element) {intern = nyt objekt [] {element}; returner sandt; }

Selvom testen består, er den tilføje metoden dækker ikke alle sager endnu. Hvis vi føjer et andet element til listen, går det eksisterende element tabt.

7.2. Anden cyklus

Her er en anden test, der tilføjer kravet om, at listen kan indeholde mere end et element:

@Test offentlig ugyldighed givenListWithAnElement_whenAnotherIsAdded_thenGetReturnsBoth () {List list = new CustomList (); list.add ("baeldung"); list.add (". com"); Objekt element1 = liste.get (0); Objekt element2 = liste.get (1); assertEquals ("baeldung", element1); assertEquals (". com", element2); }

Testen mislykkes, da den tilføje metode i sin nuværende form tillader ikke at tilføje mere end et element.

Lad os ændre implementeringskoden:

@ Override public boolean add (E element) {Object [] temp = Arrays.copyOf (intern, intern.længde + 1); temp [intern.længde] = element; intern = temp; returner sandt; }

Implementeringen er elegant nok, hvorfor vi ikke behøver at omlægge den.

8. Konklusion

Denne tutorial gennemgik en testdrevet udviklingsproces for at skabe en del af en brugerdefineret Liste implementering. Ved hjælp af TDD kan vi implementere krav trin for trin, samtidig med at testdækningen holdes på et meget højt niveau. Implementeringen er også garanteret at kunne testes, da den blev oprettet for at få testene til at bestå.

Bemærk, at den brugerdefinerede klasse, der er oprettet i denne artikel, bare bruges til demonstrationsformål og ikke bør vedtages i et virkeligt projekt.

Den komplette kildekode til denne vejledning, inklusive test- og implementeringsmetoder, der er udeladt for kortfattethed, kan findes på GitHub.