Wanneer schrijf je de "echte" code in TDD?

johnny 08/19/2017. 11 answers, 20.464 views
tdd

Alle voorbeelden die ik heb gelezen en gezien over trainingsvideo's hebben simplistische voorbeelden. Maar wat ik niet zie als ik de "echte" code doe nadat ik groen ben geworden. Is dit het gedeelte "Refactor"?

Als ik een vrij complex object heb met een complexe methode en ik schrijf mijn test en het absolute minimum om het te laten slagen (nadat het eerst is mislukt, rood). Wanneer ga ik terug en schrijf ik de echte code? En hoeveel echte code schrijf ik voordat ik opnieuw test? Ik vermoed dat die laatste meer intuïtie is.

Edit: Dank aan allen die hebben geantwoord. Al je antwoorden hebben me enorm geholpen. Er lijken verschillende ideeën te zijn over wat ik vroeg of verwarde, en misschien is dat wel zo, maar wat ik vroeg was, stel ik heb een aanvraag voor het bouwen van een school.

In mijn ontwerp heb ik een architectuur waarmee ik wil beginnen, User Stories, enzovoort. Vanaf hier neem ik die gebruikersverhalen en maak ik een test om het gebruikersverhaal te testen. De gebruiker zegt: we hebben mensen die zich inschrijven voor school en inschrijfgeld betalen. Dus, ik denk aan een manier om dat te laten mislukken. Daarbij ontwerp ik een testklasse voor klasse X (misschien Student), die zal falen. Ik maak vervolgens de klas 'Student'. Misschien "School" weet ik niet.

Maar in ieder geval dwingt de TD Design me door het verhaal te denken. Als ik een test kan laten mislukken, weet ik waarom het mislukt, maar dit veronderstelt dat ik het kan laten slagen. Het gaat over het ontwerpen.

Ik vergelijk dit met het denken aan Recursie. Recursie is geen moeilijk concept. Het is misschien moeilijker om het echt in je hoofd bij te houden, maar in werkelijkheid is het moeilijkste om te weten, wanneer de recursie "breekt", wanneer te stoppen (mijn mening, natuurlijk.) Dus ik moet nadenken over wat stopt de Recursie eerst. Het is slechts een onvolmaakte analogie, en het veronderstelt dat elke recursieve iteratie een 'doorgang' is. Nogmaals, alleen een mening.

In uitvoering is de school moeilijker te zien. Numerieke en bankreferenties zijn "eenvoudig" in die zin dat u eenvoudige rekenkunde kunt gebruiken. Ik kan een + b zien en 0 teruggeven, enz. In het geval van een systeem van mensen, moet ik er meer over nadenken hoe ik dat moet implement . Ik heb het concept van de mislukking, pass, refactor (voornamelijk vanwege studie en deze vraag.)

Wat ik niet weet, is naar mijn mening gebaseerd op een gebrek aan ervaring. Ik weet niet hoe ik moet falen bij het aanmelden voor een nieuwe student. Ik weet niet hoe ik kan nalaten iemand die een achternaam invoert en die wordt opgeslagen in een database. Ik weet hoe ik een + 1 kan maken voor eenvoudige wiskunde, maar met entiteiten als een persoon, ik weet niet of ik alleen maar test om te zien of ik een database-unieke ID of iets anders terug krijg als iemand een naam invoert in een database of beide of geen van beide.

Of misschien laat dit zien dat ik nog steeds in de war ben.

5 Comments
187 hobbs 07/25/2017
Nadat de TDD-mensen naar huis gaan voor de nacht.
14 Goyo 07/25/2017
Waarom denk je dat de code die je hebt geschreven niet echt is?
2 johnny 07/26/2017
@RubberDuck Meer dan de andere antwoorden deden. Ik weet zeker dat ik er binnenkort naar zal verwijzen. Het is nog steeds een beetje vreemd, maar ik ga het niet opgeven. Wat je zei, was logisch. Ik probeer het gewoon logisch te maken in mijn context of een reguliere zakelijke toepassing. Misschien een inventarisatiesysteem of iets dergelijks. Ik moet het overwegen. Ik ben echter dankbaar voor je tijd. Bedankt.
1 Edmund Reed 07/26/2017
De antwoorden raken al de spijker op het hoofd, maar zolang al je tests slagen en je geen nieuwe tests / functionaliteit nodig hebt, kan worden aangenomen dat de code die je hebt is voltooid, bar plukken.
3 Borjab 07/26/2017
Er is een aanname in de vraag die problematisch kan zijn in "Ik heb een vrij complex object met een complexe methode". In TDD schrijf je eerst je tests zodat je begint met een vrij eenvoudige code. Dit zal je dwingen om een ​​testvriendelijke structuur te coderen die modulair moet zijn. Dus complex gedrag wordt gecreëerd door eenvoudigere objecten te combineren. Als je eindigt met een vrij complex object of een complexe methode, dan is dat wanneer je refactoreert

11 Answers


RubberDuck 07/27/2017.

Als ik een vrij complex object heb met een complexe methode en ik schrijf mijn test en het absolute minimum om het te laten slagen (nadat het eerst is mislukt, rood). Wanneer ga ik terug en schrijf ik de echte code? En hoeveel echte code schrijf ik voordat ik opnieuw test? Ik vermoed dat die laatste meer intuïtie is.

U "gaat niet terug" en schrijft "echte code". Het is allemaal echte code. Wat u doet is teruggaan en een nieuwe test toevoegen die u forces uw code te change om de nieuwe test door te laten gaan.

Wat betreft de code die je schrijft voordat je opnieuw test? Geen. Je schrijft zero code zonder een falende test die je forces meer code te schrijven.

Let op het patroon?

Laten we door (een ander) eenvoudig voorbeeld lopen in de hoop dat het helpt.

 Assert.Equal("1", FizzBuzz(1)); 

Makkelijk peazy.

 public String FizzBuzz(int n) {
    return 1.ToString();
} 

Niet wat je echte code zou noemen, toch? Laten we een test toevoegen die een verandering afdwingt.

 Assert.Equal("2", FizzBuzz(2)); 

We kunnen iets dwaas doen, zoals if n == 1 , maar we gaan gewoon door met de gezonde oplossing.

 public String FizzBuzz(int n) {
    return n.ToString();
} 

Koel. Dit werkt voor alle niet-FizzBuzz-nummers. Wat is de volgende invoer die de productiecode zal veranderen?

 Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
} 

En opnieuw. Schrijf een test die nog niet voorbij is.

 Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
} 

En we hebben nu alle veelvouden van drie bedekt (die zijn ook geen veelvouden van vijf, we zullen het opmerken en terugkomen).

We hebben nog geen test voor 'Buzz' geschreven, dus laten we dat schrijven.

 Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
} 

En nogmaals, we weten dat er een ander geval is dat we moeten behandelen.

 Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
} 

En nu kunnen we alle veelvouden van 5 behandelen die niet ook veelvouden van 3 zijn.

Tot nu toe hebben we de stap over refactoren genegeerd, maar ik zie wat dubbel werk. Laten we dat nu opruimen.

 private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Koel. Nu hebben we de duplicatie verwijderd en een welbekende functie gemaakt. Wat is de volgende test die we kunnen schrijven die ons dwingt de code te wijzigen? Nou, we hebben het geval vermeden waarbij het nummer deelbaar is door zowel 3 als 5. Laten we het nu schrijven.

 Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

De tests gaan voorbij, maar we hebben meer duplicatie. We hebben opties, maar ik zal een paar keer "Lokale Variabelextractie" toepassen, zodat we refactoren in plaats van herschrijven.

 public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

En we hebben elke redelijke input behandeld, maar hoe zit het met unreasonable input? Wat gebeurt er als we 0 of negatief doorgeven? Schrijf die testgevallen.

 public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Begint dit er al uit te zien als "echte code"? Wat nog belangrijker was, wanneer stopte het "onwerkelijke code" te zijn en de overgang naar "echt" te zijn? Dat is iets om over na te denken ...

Dus ik kon dit eenvoudig doen door te zoeken naar een test waarvan ik wist dat die bij elke stap niet zou slagen, maar ik heb veel oefening gehad. Als ik op mijn werk ben, zijn dingen niet zo eenvoudig en ik weet misschien niet altijd welke test een verandering zal forceren. Soms schrijf ik een test en ben verrast dat het al voorbij is! Ik raad ten zeerste aan dat je de gewoonte krijgt om een ​​"testlijst" te maken voordat je begint. Deze testlijst moet alle "interessante" ingangen bevatten die u maar kunt bedenken. Je kunt ze misschien niet allemaal gebruiken en je zult waarschijnlijk cases toevoegen als je gaat, maar deze lijst dient als een routekaart. Mijn testlijst voor FizzBuzz zou er ongeveer zo uitzien.

  • Negatief
  • Nul
  • een
  • Twee
  • Drie
  • Vier
  • Vijf
  • Zes (niet-triviale veelvoud van 3)
  • Negen (3 kwadraat)
  • Ten (niet-triviaal veelvoud van 5)
  • 15 (veelvoud van 3 en 5)
  • 30 (niet-triviale veelvoud van 3 en 5)
5 comments
3 maple_shaft♦ 07/27/2017
Opmerkingen zijn niet voor uitgebreide discussie; dit gesprek is verplaatst naar chat .
40 GManNickG 07/27/2017
Tenzij ik dit antwoord volledig verkeerd begrijp: "We zouden iets dwaas kunnen doen, zoals n == 1, maar we gaan gewoon door met de gezonde oplossing." - het hele ding was dom. Als je van te voren weet, wil je een functie die <spec> doet, schrijftests voor <spec> en sla het gedeelte over waar je versies schrijft die duidelijk falen <spec>. Als u een fout in <spec> vindt, moet u dit zeker weten: schrijf eerst een test om te controleren of u deze vóór de fix kunt uitproberen en observeer de testpassages na de fix. Maar het is niet nodig om al deze tussenstappen te vervalsen.
15 user3791372 07/28/2017
De opmerkingen die wijzen op de grote tekortkomingen in dit antwoord en TDD in het algemeen zijn verplaatst naar chat. Als u overweegt om TDD te gebruiken, lees dan de 'chat'. Helaas zijn de 'kwaliteits'-commentaren nu verborgen onder een lading chat voor toekomstige studenten om te lezen.
nbro 07/28/2017
Ik zou nauwkeuriger zijn met betrekking tot de inhoud van deze "testlijst", als u dit antwoord wilde verbeteren. Ik zou expliciet spreken over "grenswaarden" en "klasse partitionering".
2 hvd 07/30/2017
@GManNickG Ik geloof dat het erom gaat de juiste hoeveelheid tests te krijgen. Het vooraf schrijven van de tests maakt het gemakkelijk om te missen welke speciale gevallen moeten worden getest, wat leidt tot situaties die niet voldoende worden afgedekt in de tests, of tot in essentie dezelfde situatie onnodig veelvuldig wordt afgedekt tijdens de tests. Als je dat kunt doen zonder deze tussenstappen, geweldig! Niet iedereen kan dit echter al doen, het is iets dat oefening vereist.

GenericJon 07/24/2017.

De "echte" code is de code die u schrijft om uw test te laten slagen. Really . Het is zo simpel.

Wanneer mensen het over het absolute minimum hebben om de test groen te maken, betekent dit alleen dat uw echte code het YAGNI-principe moet volgen.

Het idee van de refactorstap is alleen om op te ruimen wat u hebt geschreven als u tevreden bent dat het aan de vereisten voldoet.

Zolang de tests die u schrijft ook uw productvereisten omvatten, is de code eenmaal voltooid. Denk er eens over na, als al uw bedrijfsvereisten een test hebben en al die tests groen zijn, wat is er dan nog meer om te schrijven? (Oké, in het echte leven hebben we niet de neiging volledige testverslagen te hebben, maar de theorie is goed.)

5 comments
44 Derek Elkins 07/24/2017
Testeenheden kunnen uw productvereisten niet omvatten voor zelfs relatief triviale vereisten. In het beste geval samplen ze de invoer-uitvoerruimte en het idee is dat je (correct) generaliseert naar de volledige invoer-uitvoerruimte. Natuurlijk kan uw code gewoon een grote switch met een case voor elke unit-test die alle tests zou doorstaan ​​en faalt voor andere ingangen.
8 Taemyr 07/25/2017
@ DerekElkins TDD machtigt falende tests. Niet falen unit tests.
6 jonrsharpe 07/25/2017
@ DerekElkins daarom schrijf je niet alleen eenheidstests, en ook waarom er een algemene aanname is dat je iets probeert te maken dat niet alleen maar nep is!
35 Derek Elkins 07/25/2017
@jonrsharpe Volgens die logica zou ik nooit triviale implementaties schrijven. Voorbeeld: in het antwoord van FizzBuzz in het antwoord van RubberDuck (dat alleen unit tests gebruikt), is de eerste implementatie duidelijk "gewoon een fake". Mijn begrip van de vraag is precies deze dichotomie tussen het schrijven van code waarvan je weet dat deze onvolledig is en de code waarvan je echt denkt dat deze de vereiste, de 'echte code' zal implementeren. Mijn "grote switch " was bedoeld als een logisch uiterste van "het absolute minimum schrijven om de tests groen te maken". Ik beschouw de vraag van het OP als: waar in TDD is het principe dat deze grote switch vermijdt?
2 Luaan 07/25/2017
@GenericJon Dat is een beetje te optimistisch in mijn ervaring :) Ten eerste zijn er mensen die genieten van gedachteloos repetitief werk. Ze zullen gelukkiger zijn met een gigantische switch-statement dan met een "gecompliceerde besluitvorming". En om hun baan te verliezen, hebben ze of iemand nodig die ze oproept met de techniek (en ze hebben beter goed bewijs dat ze de kansen / het geld van het bedrijf verliezen!), Of ze doen het uitzonderlijk slecht. Na het overnemen van het onderhoud van veel van dergelijke projecten, kan ik zeggen dat het gemakkelijk is voor zeer naïeve code om tientallen jaren mee te gaan, zolang het de klant maar blij maakt (en betaalt).

Carl Raymond 07/24/2017.

Het korte antwoord is dat de "echte code" de code is die de test doet slagen. Als u uw test kunt laten slagen met iets anders dan echte code, voegt u meer tests toe!

Ik ben het ermee eens dat veel tutorials over TDD simplistisch zijn. Dat werkt tegen hen. Een te simpele test voor een methode die bijvoorbeeld 3 + 8 berekent, heeft echt geen andere keus dan ook 3 + 8 te berekenen en het resultaat te vergelijken. Daardoor lijkt het alsof je code gewoon overal dupliceert, en dat testen zinloos is, foutgevoelig extra werk.

Wanneer u goed bent in het testen, zal dat aangeven hoe u uw applicatie structureert en hoe u uw code schrijft. Als je moeite hebt met het bedenken van zinvolle, behulpzame tests, zou je je ontwerp waarschijnlijk een beetje moeten heroverwegen. Een goed ontworpen systeem is eenvoudig te testen - wat betekent dat zinvolle tests gemakkelijk te bedenken en uit te voeren zijn.

Wanneer u eerst uw tests schrijft, let op ze falen en schrijf dan de code waarmee ze slagen, dat is een discipline om ervoor te zorgen dat al uw code overeenkomstige tests heeft. Ik volg die regel niet slaafs als ik codeer; vaak schrijf ik tests achter het feit. Maar eerst testen doen, helpt je eerlijk te blijven. Met wat ervaring zul je merken dat je jezelf in een hoek codeert, zelfs als je niet eerst tests schrijft.

4 comments
6 Steve Jessop 07/26/2017
Persoonlijk zou de test die ik zou schrijven assertEqual(plus(3,8), 11) , niet assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)) . Voor complexere gevallen zoekt u altijd naar een middel om het resultaat correct te bewijzen, other than dynamisch het juiste resultaat in de test te berekenen en gelijkheid te controleren.
Steve Jessop 07/26/2017
Dus voor een echt dwaze manier om dit voor dit voorbeeld te doen, zou je kunnen bewijzen dat plus(3,8) het juiste resultaat heeft teruggegeven door er 3 van af te trekken, 8 ervan af te trekken, en het resultaat tegen 0 te controleren. Dit is zo vanzelfsprekend equivalent aan assertEqual(plus(3,8), 3+8) om een ​​beetje absurd te zijn, maar als de te testen code iets gecompliceerder maakt dan alleen een geheel getal, dan is het nemen van het resultaat en het controleren van elk onderdeel op juistheid vaak de juiste aanpak. Als alternatief, zoiets als for (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Steve Jessop 07/26/2017
... aangezien dat de grote angst vermijdt, wat inhoudt dat we bij het schrijven van de test dezelfde fout maken met betrekking tot het onderwerp "hoe toe te voegen 10" dat we in de live code hebben gemaakt. Dus de test vermijdt voorzichtig het schrijven van een code die er 10 aan toevoegt, in de test kan plus() 10 dingen toevoegen. We vertrouwen natuurlijk nog altijd op de door de programmeur geverifieerde waarden voor de beginlus.
3 Warbo 07/28/2017
Ik wil u erop wijzen dat zelfs als u achteraf tests schrijft, het nog steeds een goed idee is om ze te laten mislukken; vind een deel van de code dat cruciaal lijkt voor alles waar je aan werkt, tweak het een beetje (bijv. vervang een + door een - of wat dan ook), voer de tests uit en bekijk ze falen, maak de verandering ongedaan en kijk ze voorbij. Vaak heb ik dit gedaan, maar de test faalt eigenlijk niet, waardoor het slechter dan nutteloos wordt: het is niet alleen niets testen, het geeft me het valse vertrouwen dat er iets wordt getest!

Victor Cejudo 07/25/2017.

Soms zijn enkele voorbeelden van TDD misleidend. Zoals andere mensen al eerder hebben opgemerkt, is de code die je schrijft om tests te laten slagen de echte code.

Maar denk niet dat de echte code lijkt op magie - dat klopt niet. U moet een beter begrip hebben van wat u wilt bereiken en vervolgens moet u de test overeenkomstig kiezen, te beginnen bij de eenvoudigste cases en cases in de hoek.

Als u bijvoorbeeld een lexer wilt schrijven, begint u met een lege tekenreeks, vervolgens met een aantal witruimten, vervolgens een cijfer, vervolgens met een getal omringd door witruimten, dan een verkeerd getal, enz. Deze kleine transformaties leiden u naar het juiste algoritme, maar je springt niet van het eenvoudigste naar een uiterst complexe case die je dom hebt gekozen om de echte code te krijgen.

Bob Martin legt het hier perfect uit.


CandiedOrange 07/25/2017.

Het refactordeel wordt opgeruimd als je moe bent en naar huis wilt.

Wanneer u een functie gaat toevoegen, is het refactor-gedeelte wat u wijzigt vóór de volgende test. Je refactor de code om ruimte te maken voor de nieuwe functie. U doet dit wanneer u know wat die nieuwe functie zal zijn. Niet als je het je gewoon verbeeldt.

Dit kan zo simpel zijn als het hernoemen van GreetImpl naar GreetWorld voordat u een GreetMom klasse maakt (na het toevoegen van een test) om een ​​functie toe te voegen die "Hallo mama" zal afdrukken.


graeme 07/27/2017.

Maar de echte code zou verschijnen in de refactor-fase van de TDD-fase. Dwz de code die deel moet uitmaken van de definitieve versie.

Tests moeten worden uitgevoerd elke keer dat u een wijziging aanbrengt.

Het motto van de TDD-levenscyclus zou zijn: RODE GROENE REFACTOR

RED : schrijf de tests

GREEN : doe een eerlijke poging om functionele code te krijgen die tests zo snel mogelijk doorgeeft: dubbele code, obsceen benoemde variabelen hacks van de hoogste orde, etc.

REFACTOR : Maak de code op, noem de variabelen op de juiste manier. DROOG de code op.

5 comments
5 mcottle 07/25/2017
Ik weet wat u zegt over de "groene" fase, maar het impliceert dat hardbedrade retourwaarden om de tests te laten slagen, geschikt kunnen zijn. In mijn ervaring zou "Groen" een eerlijke poging moeten zijn om werkcode te maken om aan de vereiste te voldoen, maar het zou niet perfect kunnen zijn, maar het zou zo volledig en "verzendbaar" moeten zijn als de ontwikkelaar in een eerste doorgang kan beheren. Refactoring is waarschijnlijk het best gedaan enige tijd later nadat je meer hebt gedaan en de problemen met de eerste pass duidelijker worden en er mogelijkheden voor DRY ontstaan.
graeme 07/25/2017
@mcottle ik beschouw deze allemaal als onderdeel van dezelfde taak. maak het klaar en ruim het op. Verdere refactorings zouden in de loop van de tijd moeten plaatsvinden als onderdeel van andere taken.
1 Bryan Boettcher 07/25/2017
@mcottle: je zou verbaasd zijn hoeveel implementaties van een get-only repository hardcoded waarden kunnen zijn in de codebase. :)
6 Kaz 07/25/2017
Waarom zou ik ooit onzincode schrijven en opruimen, wanneer ik bijna net zo snel als de typecode van de productiekwaliteit kan draaien? :)
1 Kaz 07/27/2017
@TimothyTruckle Wat kost het als er 50 minuten nodig zijn om de eenvoudigst mogelijke wijziging te vinden, maar slechts 5 om de op één na simpelste wijziging te vinden? Gaan we met de eenvoudigste of blijven we zoeken naar de eenvoudigste?

Timothy Truckle 07/27/2017.

Wanneer schrijf je de "echte" code in TDD?

De red fase is waar je code write .

In de fase van refactoring is het primaire doel om code te delete .

In de red fase doet u er alles aan om de test as quick as possible en at any cost te laten slagen. Je negeert volledig wat je ooit hebt gehoord over goede codeermethoden of hetzelfde ontwerppatroon. Het is belangrijk om de test groen te maken.

In de fase van refactoring ruim je de rommel op die je zojuist hebt gemaakt. Nu kijk je eerst of de verandering die je zojuist hebt gemaakt de beste is in de lijst Transformation Priority en of er een codeduplicatie is die je hoogstwaarschijnlijk kunt verwijderen door een design-patter toe te passen.

Eindelijk verbetert u de leesbaarheid door namen te hernoemen en magic numbers en / of letterlijke reeksen naar constanten te extraheren.


Het is geen rode refactor, het is rood-groen-refactor. - Rob Kinyon

Bedankt dat je dit hebt gewezen.

Het is dus de green fase waarin je de real code schrijft

In de red fase schrijf je de executable specification ...

2 comments
Rob Kinyon 07/27/2017
Het is geen rode refactor, het is rood-groen-refactor. Het "rode" is dat u uw testsuite van groen neemt (alle tests slagen) naar rood (één test mislukt). Het "groene" is waar je slordig je testsuite van rood neemt (één test mislukt) naar groen (alle tests slagen er in). De "refactor" is waar je je code neemt en het mooi maakt terwijl alle tests voorbij gaan.
Timothy Truckle 07/27/2017
@RobKinyon Bedankt, het antwoord bijgewerkt.

Robert Andrzejuk 07/27/2017.

Je schrijft de hele tijd de Real Code .

Bij elke stap schrijft U code om te voldoen aan de voorwaarden die Uw code zal vervullen voor toekomstige bellers van Uw code (die U zou kunnen zijn of niet ...).

Je denkt dat je geen nuttige ( real ) code schrijft, omdat je het in een ogenblik zou kunnen refacteren.

Code-Refactoring is het proces van het herstructureren van bestaande computercodes die de factoring veranderen, zonder het externe gedrag ervan te veranderen.

Wat dit betekent is dat, hoewel u de code wijzigt, de voorwaarden waaraan de code voldoet, ongewijzigd blijven. En de controles ( tests ) die u hebt uitgevoerd om te verifiëren dat uw code al aanwezig is om te controleren of uw wijzigingen iets hebben gewijzigd. Dus de code die je de hele tijd hebt geschreven staat daarin, alleen op een andere manier.

Nog een reden. Je zou kunnen denken dat het geen echte code is, maar dat je voorbeelden aan het doen bent waarbij het eindprogramma al door jou kan worden voorzien. Dit is erg goed, want het laat zien dat je kennis hebt over het domain je programmeert.
Maar vele malen zitten programmeurs in een domain dat new , unknown voor hen. Ze weten niet wat het eindresultaat zal zijn en TDD is een technique om stapsgewijs programma's te schrijven, waarin onze knowledge wordt gedocumenteerd over hoe dit systeem zou moeten werken en dat onze code op die manier werkt.

Toen ik The Book (*) op TDD las, was voor mij de belangrijkste functie die opviel de: TODO-lijst. Het heeft mij laten zien dat TDD ook een techniek is om ontwikkelaars te helpen zich op één ding tegelijk te concentreren. Dus dit is ook een antwoord op Uw vraag over How much Real code to write ? Ik zou genoeg code zeggen om me op één ding tegelijk te concentreren.

(*) "Test Driven Development: By Example" door Kent Beck

1 comments
2 Robert Andrzejuk 07/27/2017
"Test Driven Development: By Example" door Kent Beck

Zenilogix 07/31/2017.

Je schrijft geen code om je tests te laten mislukken.

U schrijft uw tests om te definiëren hoe succes eruit moet zien, wat in eerste instantie zou mislukken omdat u de code nog niet hebt geschreven.

Het hele punt over het schrijven van in eerste instantie falende tests is om twee dingen te doen:

  1. Behandel alle gevallen - alle nominale zaken, alle randgevallen, enz.
  2. Valideer uw tests. Als u ze alleen maar ziet passeren, hoe kunt u er dan zeker van zijn dat ze een fout betrouwbaar melden als er zich een voordoet?

Het punt achter rood-groen-refactor is dat het schrijven van de juiste tests eerst het vertrouwen geeft om te weten dat de code die je hebt geschreven om de tests te halen correct is, en stelt je in staat te refactoren met het vertrouwen dat je tests je zo snel mogelijk zullen informeren er breekt iets, dus je kunt meteen teruggaan om het te repareren.

In mijn eigen ervaring (C # / .NET) is pure test-first een beetje een onbereikbaar ideaal, omdat je een call niet kunt samenstellen tot een methode die nog niet bestaat. Dus "eerst testen" gaat in feite over het coderen van interfaces en het stubbing van implementaties, dan het schrijven van tests tegen de stubs (die aanvankelijk zullen falen) totdat de stubs correct zijn uitgewerkt. Ik schrijf nooit "falende code", maar bouw gewoon op van stubs.


Zan Lynx 07/27/2017.

Ik denk dat je in de war bent tussen unit tests en integratietests. Ik geloof dat er ook acceptatietests kunnen zijn, maar dat hangt af van je proces.

Zodra je alle kleine "eenheden" hebt getest, test je ze allemaal gemonteerd of "geïntegreerd". Dat is meestal een heel programma of een hele bibliotheek.

In de code die ik heb geschreven, de integratietests, een bibliotheek met verschillende testprogramma's die gegevens lezen en deze naar de bibliotheek sturen, controleer dan de resultaten. Dan doe ik het met threads. Dan doe ik het met draden en vork () in het midden. Vervolgens voer ik het uit en kill -9 na 2 seconden, dan start ik het en controleer ik de herstelmodus. Ik fuzz het. Ik martel het op allerlei manieren.

Dat is OOK testen, maar ik heb geen mooie rood / groene weergave voor de resultaten. Het lukt, of ik doorzoek een paar duizend regels foutcode om erachter te komen waarom.

Dat is waar je de "echte code" test.

En ik dacht hier net aan, maar misschien weet je niet wanneer je klaar bent met het schrijven van eenheidsonderzoeken. U bent klaar met het schrijven van eenheidscontroles wanneer uw tests alles uitvoeren dat u hebt opgegeven. Soms kun je dat van alle foutafhandeling en edge-cases uit het oog verliezen, dus misschien wil je een leuke testgroep maken met blijvende padtests die gewoon door de specificaties gaan.

1 comments
Peter Mortensen 07/27/2017
(zijn = bezittelijk, het is = "het is" of "het heeft". Zie bijvoorbeeld How to Use Its and It's .)

user3791372 07/27/2017.

In antwoord op de titel van de vraag: "Wanneer schrijf je de" echte "code in TDD?", Luidt het antwoord: 'bijna nooit' of 'heel langzaam'.

Je klinkt als een student, dus ik zal antwoorden alsof ik een student adviseer.

Je gaat veel coderende 'theorieën' en 'technieken' leren. Ze zijn geweldig om de tijd door te brengen aan dure studentencursussen, maar weinig voordeel voor u dat u in de helft van de tijd niet in een boek kon lezen.

De taak van een codeerder is uitsluitend om code te produceren. Code die echt goed werkt. Dat is de reden waarom u, de codeur, de code in gedachten plant, op papier, in een geschikte toepassing, enz., En van plan bent om eventuele onvolmaaktheden / gaten van tevoren te omzeilen door logisch en zijwaarts te denken voordat u codeert.

Maar je moet weten hoe je je applicatie moet breken om fatsoenlijke code te kunnen ontwerpen. Als u bijvoorbeeld niet wist over Little Bobby Table (xkcd 327), zou u waarschijnlijk uw invoer niet zuiveren voordat u met de database werkt, dus u zou uw gegevens rond dat concept niet kunnen beveiligen.

TDD is slechts een workflow die is ontworpen om de fouten in uw code tot een minimum te beperken door tests te maken van wat er mis kan gaan voordat u uw toepassing codeert, omdat codering exponentieel moeilijker kan worden naarmate u meer code invoert en fouten vergeet die u ooit hebt bedacht. Als u denkt dat u klaar bent met uw toepassing, voert u de tests en de hausse uit, hopelijk worden bugs door uw tests gepakt.

TDD is niet - zoals sommige mensen geloven - een test te schrijven, het te laten passeren met minimale code, een nieuwe test te schrijven, dat te halen met minimale code, enz. In plaats daarvan is het een manier om je te helpen zelfvertrouwen te krijgen. Dit ideaal van continue refactoring code om het te laten werken met testen is idioot, maar het is een leuk concept onder studenten omdat het hen een goed gevoel geeft wanneer ze een nieuwe functie toevoegen en ze nog steeds leren coderen ...

Val alsjeblieft niet in deze valkuil en zie je codeerrol voor wat het is - het is alleen de taak van een codeerder om code te produceren. Code die echt goed werkt. Onthoud dat u op de klok bent als een professionele codeur en dat het uw cliënt niet uitmaakt of u 100.000 beweringen heeft geschreven, of 0. Ze willen gewoon code die werkt. Echt goed eigenlijk.

5 comments
3 johnny 07/25/2017
Ik sta niet eens dicht bij een student, maar ik lees wel en probeer goede technieken toe te passen en professioneel te zijn. Dus in die zin ben ik een 'student'. Ik stel gewoon heel basale vragen, want zo ben ik. Ik wil graag weten waarom ik precies doe wat ik doe. De kern van de zaak. Als ik dat niet begrijp, vind ik het niet leuk en begin ik vragen te stellen. Ik moet weten waarom, als ik het ga gebruiken. TDD lijkt in sommige opzichten intuïtief goed, zoals weten wat je nodig hebt om dingen te creëren en erover na te denken, maar de implementatie was moeilijk te begrijpen. Ik denk dat ik het nu beter begrijp.
4 Sean Burton 07/27/2017
Dat zijn de regels van TDD. Je bent vrij om code te schrijven zoals je wilt, maar als je die drie regels niet volgt, doe je TDD niet.
2 user3791372 07/27/2017
"Regels" van één persoon? TDD is een suggestie om je te helpen coderen, geen religie. Het is triest om te zien dat zoveel mensen zich zo anaal aan een idee houden. Zelfs de oorsprong van TDD is controversieel.
2 Alex 07/28/2017
@ user3791372 TDD is een zeer strikt en duidelijk gedefinieerd proces. Zelfs als velen denken dat het gewoon gemeen is "doe wat tests tijdens het programmeren", is dat niet het geval. Laten we proberen hier geen termen door elkaar te halen, deze vraag gaat over het proces-TDD, niet over algemene testen.

Related questions

Hot questions

Language

Popular Tags