Upload
joachim-lovf
View
162
Download
0
Tags:
Embed Size (px)
DESCRIPTION
Presentation (mostly in Norwegian) which quickly describes the whys, whats and hows of TDD, and then continues with classroom/workshop assignments which describe the red-green-refactor cycle, refactoring, CLEANing up code, inversion of control with dependency injection, etc. The source code examples can be viewed and downloaded from https://github.com/JoachimL/Creuna-Tdd Used to teach TDD to summer students and new employees at Creuna's Tech Lab on June 16th 2014.
Citation preview
TDD – en kjapp innføringTech-lab
16.06.2013
Click icon to add picture
Agenda
© Creuna
1. Hvorfor?2. Hva?3. Hvordan?
Hvorfor?
• Funksjonell programmering «eneste» vei fremover og oppover.• TDD er en selvsagt del av programvareleveranser med kvalitet• Det er ikke lenger et spørsmål om OM, men hvordan det gjøres best og
hvordan man best skal utnytte fordelene det gir.• Uncle Bob: One of these days, a major catastrophe will be caused by the
mistakes we do, and tens of thousands of people will die.• TDD er dobbelsikringen.
• AutoScout24: Alt man sjekker inn kan deployes når som helst.
Inntrykk fra NDC
© Creuna
58% of software bugs result from
test infrastructure and process, not design defects»
© Creuna
Vi gjør feil
Hva?
• Test algoritmer• Test DIN kode• Test enheten.• Servicen• Controlleren
• Ikke test GUI• For flyktig• EPiServer er GUI. I stor grad.
Hva skal testes?
© Creuna
Hvordan?
1. Del opp oppgaven i så små deler som mulig, og start på toppen
2. Skriv en test som tester kun funksjonaliteten beskrevet.
3. Skriv akkurat nok kode til å tilfredsstille testen i kode 2.
4. Gjør koden pen
5. Gå til steg 2
Hvordan?
© Creuna
• Fast• Independent• Repeatable• Self-checking• Timely
FIRST-prinsippet
© Creuna
• Fast• Independent• Repeatable• Self-checking• Timely
FIRST-prinsippet
© Creuna
Fast
Testene må være raske, ettersom de kjøres kontinuerlig.
• Enhetstester må være raskere enn integrasjonstester som må være raskere enn systemtester.
• Avhengigheter til andre systemer og moduler unngås, typisk med mocks og stubs.
• Et verktøy som nCrunch kan automatisk kjøre tester som berøres når kode endres.
• Det kan være en god idé å disable integrasjonstester underveis.© Creuna
• Fast• Independent• Repeatable• Self-checking• Timely
FIRST-prinsippet
© Creuna
Independent
Testene må være uavhengige av hverandre
• Tester må gi samme resultat uavhengig av rekkefølgen de blir kjørt i.
• En test kan ikke være avhengig av en annen tests resultat (eller klar over dens eksistens).
• Bruk av f.eks SetUp-attributter i nUnit for å (gjen)skape opprinnelig state.
© Creuna
• Fast• Independent• Repeatable• Self-checking• Timely
FIRST-prinsippet
© Creuna
Repeatable
Testene må gi samme resultat uavhengig av hvor mange ganger de kjøres.• Igjen ved bruk av f.eks SetUp-
attributter i nUnit for å (gjen)skape opprinnelig state.
• Unngå avhengigheter til eksterne systemer.
• Klokka er også et eksternt system!
© Creuna
• Fast• Independent• Repeatable• Self-checking• Timely
FIRST-prinsippet
© Creuna
Self-checking
Testene må automatisk vite om de er passert og godkjent.• Ingen manuelle rutiner/operasjoner
(ingen output må verifiseres manuelt eller observasjoner av annen art må gjøres).• Console.WriteLine/Debug.WriteLine etc
er unødvendig i en enhetstest.• Muliggjør CI med selvtillit • Og deretter CD.
© Creuna
• Fast• Independent• Repeatable• Self-checking• Timely
FIRST-prinsippet
© Creuna
Timely
Testene skal skrives til rett tid og alltid før systemkoden.• Enhetstester skal skrives umiddelbart
før koden den dekker.• Ikke etter
© Creuna
Kode
GitHub SSH keys: https://help.github.com/articles/generating-ssh-keys
$ git clone https://github.com/JoachimL/Creuna-Tdd.git
$ git checkout tags/01-Before
• StringCalculator – appen/biblioteket som testes• StringCalculator.UnitTests - enhetstestene
StringCalculator
© Creuna
Verktøy
• nUnit• Testrammeverket• Should• Extensions/Test
Assertions• .ShouldEqual• .ShouldNotBeNull
© Creuna
• AutoFixture• Skaper testdata• Moq• Mocking-rammeverk
Skriv en enkel String-kalkulator som summerer tall gitt som strenge-input.1. Om input er en tom streng, skal kalkulatoren returnere 0.2. Om input er ett enkelt tall (”1”, ”68”), skal tallet (1, 68) returneres.3. Om input er to tall (”1,2”), skal summen av tallene (3) returneres.4. La antall tall være vilkårlig (”1,2”, ”1,2,3,4,5,6”)5. La linjeskift være gyldig separator6. La separatoren være konfigurerbar. Om den første linjen begynner med
”//”, skal tegnet etter ”//” være separator. F.eks ”//;”.
StringCalculator
© Creuna
Om input er en tom streng, skal kalkulatoren returnere 0.
© Creuna
Påstand
«System Under Test»
Samme namespace som klassen somtestes
Kjøres før hver test
Om input er en tom streng, skal kalkulatoren returnere 0.
© Creuna
Om input er en tom streng, skal kalkulatoren returnere 0.
© Creuna
Implementert...
© Creuna
Skriv en enkel String-kalkulator som summerer tall gitt som strenge-input.1. Om input er en tom streng, skal kalkulatoren returnere 0.2. Om input er ett enkelt tall (”1”, ”68”), skal tallet (1, 68) returneres.3. Om input er to tall (”1,2”), skal summen av tallene (3) returneres.4. La linjeskift være gyldig separator5. La separatoren være konfigurerbar. Om den første linjen begynner med
”//”, skal tegnet etter ”//” være separator. F.eks ”//;”.
StringCalculator
© Creuna
git checkout tags/02-Refactor
Input er ett tall – tallet skal returneres - testen
© Creuna
git checkout tags/02-Refactor
Input er ett tall – tallet skal returneres - testen
© Creuna
git checkout tags/02-Refactor
Input er ett tall – tallet skal returneres
© Creuna
git checkout tags/02-Refactor-done
Input er ett tall – tallet skal returneres
© Creuna
git checkout tags/02-Refactor-done
Input er ett tall – tallet skal returneres - implementert
© Creuna
Skriv en enkel String-kalkulator som summerer tall gitt som strenge-input.1. Om input er en tom streng, skal kalkulatoren returnere 0.2. Om input er ett enkelt tall (”1”, ”68”), skal tallet (1, 68) returneres.3. Om input er to tall (”1,2”), skal summen av tallene (3) returneres.4. La linjeskift være gyldig separator5. La separatoren være konfigurerbar. Om den første linjen begynner med
”//”, skal tegnet etter ”//” være separator. F.eks ”//;”.
StringCalculator
© Creuna
git checkout tags/04-Generic-MultipleNumbers-implemented
Om input er to tall skal summen av tallene returneres - testen
© Creuna
git checkout tags/04-Generic-MultipleNumbers-implemented
Om input er to tall skal summen av tallene returneres - implementert
© Creuna
git checkout tags/05-Refactored-to-linq
Om input er to tall skal summen av tallene returneres - refactored
© Creuna
Om input er to tall skal summen av tallene returneres – refactored (2)
© Creuna
Skriv en enkel String-kalkulator som summerer tall gitt som strenge-input.1. Om input er en tom streng, skal kalkulatoren returnere 0.2. Om input er ett enkelt tall (”1”, ”68”), skal tallet (1, 68) returneres.3. Om input er to tall (”1,2”), skal summen av tallene (3) returneres.4. La linjeskift være gyldig separator.5. La separatoren være konfigurerbar. Om den første linjen begynner med
”//”, skal tegnet etter ”//” være separator. F.eks ”//;”.
Utfordringen
© Creuna
git checkout tags/06-line-break-test-added
La linjeskift være gyldig separator
© Creuna
Skriv en enkel String-kalkulator som summerer tall gitt som strenge-input.1. Om input er en tom streng, skal kalkulatoren returnere 0.2. Om input er ett enkelt tall (”1”, ”68”), skal tallet (1, 68) returneres.3. Om input er to tall (”1,2”), skal summen av tallene (3) returneres.4. La linjeskift være gyldig separator5. La separatoren være konfigurerbar. Om den første linjen begynner med
”//”, skal tegnet etter ”//” være separator. F.eks ”//;”.
StringCalculator
© Creuna
git checkout tags/08-Custom-delimiters-test
La separatoren være konfigurerbar - test
© Creuna
//;1;45;67;89Eller//|8|76|844|1|
git checkout tags/09-Custom-delimiters-implementation
La separatoren være konfigurerbar - implementering
© Creuna
© Creuna
«I want all the numbers!»
-Angry Boss
git checkout tags/10-CalculationAggregator
1. If the calculation result is bigger than 0, post result to aggregator
StringCalculator - Aggregeringsservice
© Creuna
• Send alle resultater til en ekstern webservice.• Kalkulatoren sier ifra til sine brukere at den trenger webservicen.• Inversion of control – kalkulatoren forteller hva den trenger, det er opp til det brukerne å
tilfredsttille kravene.
• Dependency Injection• I constructor. Et godt steg mot immutability.
• Vi vil ikke teste et faktisk kall mot en web service i en enhetstest. Derfor mocker vi web servicen.
StringCalculator - fortsettes
© Creuna
git checkout tags/10-CalculationAggregator
1. If the Post fails (returns false), throw an Exception.2. If the calculation result is bigger than 0, post result to aggregator3. Ignore any number bigger than 1000.4. Throw an exception if the calculation result is less than zero.
StringCalculator - Aggregeringsservice
© Creuna
GOD sommer!