49
TDD – en kjapp innføring Tech-lab 16.06.2013

Creuna TDD workshop

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

Page 1: Creuna TDD workshop

TDD – en kjapp innføringTech-lab

16.06.2013

Page 2: Creuna TDD workshop

Click icon to add picture

Agenda

© Creuna

1. Hvorfor?2. Hva?3. Hvordan?

Page 3: Creuna TDD workshop

Hvorfor?

Page 4: Creuna TDD workshop

• 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

Page 5: Creuna TDD workshop

58% of software bugs result from

test infrastructure and process, not design defects»

© Creuna

Vi gjør feil

Page 6: Creuna TDD workshop

Hva?

Page 7: Creuna TDD workshop

• Test algoritmer• Test DIN kode• Test enheten.• Servicen• Controlleren

• Ikke test GUI• For flyktig• EPiServer er GUI. I stor grad.

Hva skal testes?

© Creuna

Page 8: Creuna TDD workshop

Hvordan?

Page 9: Creuna TDD workshop

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

Page 10: Creuna TDD workshop

• Fast• Independent• Repeatable• Self-checking• Timely

FIRST-prinsippet

© Creuna

Page 11: Creuna TDD workshop

• Fast• Independent• Repeatable• Self-checking• Timely

FIRST-prinsippet

© Creuna

Page 12: Creuna TDD workshop

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

Page 13: Creuna TDD workshop

• Fast• Independent• Repeatable• Self-checking• Timely

FIRST-prinsippet

© Creuna

Page 14: Creuna TDD workshop

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

Page 15: Creuna TDD workshop

• Fast• Independent• Repeatable• Self-checking• Timely

FIRST-prinsippet

© Creuna

Page 16: Creuna TDD workshop

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

Page 17: Creuna TDD workshop

• Fast• Independent• Repeatable• Self-checking• Timely

FIRST-prinsippet

© Creuna

Page 18: Creuna TDD workshop

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

Page 19: Creuna TDD workshop

• Fast• Independent• Repeatable• Self-checking• Timely

FIRST-prinsippet

© Creuna

Page 20: Creuna TDD workshop

Timely

Testene skal skrives til rett tid og alltid før systemkoden.• Enhetstester skal skrives umiddelbart

før koden den dekker.• Ikke etter

© Creuna

Page 21: Creuna TDD workshop

Kode

Page 22: Creuna TDD workshop

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

Page 23: Creuna TDD workshop

Verktøy

• nUnit• Testrammeverket• Should• Extensions/Test

Assertions• .ShouldEqual• .ShouldNotBeNull

© Creuna

• AutoFixture• Skaper testdata• Moq• Mocking-rammeverk

Page 24: Creuna TDD workshop

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

Page 25: Creuna TDD workshop

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

Page 26: Creuna TDD workshop

Om input er en tom streng, skal kalkulatoren returnere 0.

© Creuna

Page 27: Creuna TDD workshop

Om input er en tom streng, skal kalkulatoren returnere 0.

© Creuna

Page 28: Creuna TDD workshop

Implementert...

© Creuna

Page 29: Creuna TDD workshop

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

Page 30: Creuna TDD workshop

git checkout tags/02-Refactor

Input er ett tall – tallet skal returneres - testen

© Creuna

Page 31: Creuna TDD workshop

git checkout tags/02-Refactor

Input er ett tall – tallet skal returneres - testen

© Creuna

Page 32: Creuna TDD workshop

git checkout tags/02-Refactor

Input er ett tall – tallet skal returneres

© Creuna

Page 33: Creuna TDD workshop

git checkout tags/02-Refactor-done

Input er ett tall – tallet skal returneres

© Creuna

Page 34: Creuna TDD workshop

git checkout tags/02-Refactor-done

Input er ett tall – tallet skal returneres - implementert

© Creuna

Page 35: Creuna TDD workshop

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

Page 36: Creuna TDD workshop

git checkout tags/04-Generic-MultipleNumbers-implemented

Om input er to tall skal summen av tallene returneres - testen

© Creuna

Page 37: Creuna TDD workshop

git checkout tags/04-Generic-MultipleNumbers-implemented

Om input er to tall skal summen av tallene returneres - implementert

© Creuna

Page 38: Creuna TDD workshop

git checkout tags/05-Refactored-to-linq

Om input er to tall skal summen av tallene returneres - refactored

© Creuna

Page 39: Creuna TDD workshop

Om input er to tall skal summen av tallene returneres – refactored (2)

© Creuna

Page 40: Creuna TDD workshop

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

Page 41: Creuna TDD workshop

git checkout tags/06-line-break-test-added

La linjeskift være gyldig separator

© Creuna

Page 42: Creuna TDD workshop

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

Page 43: Creuna TDD workshop

git checkout tags/08-Custom-delimiters-test

La separatoren være konfigurerbar - test

© Creuna

//;1;45;67;89Eller//|8|76|844|1|

Page 44: Creuna TDD workshop

git checkout tags/09-Custom-delimiters-implementation

La separatoren være konfigurerbar - implementering

© Creuna

Page 45: Creuna TDD workshop

© Creuna

«I want all the numbers!»

-Angry Boss

Page 46: Creuna TDD workshop

git checkout tags/10-CalculationAggregator

1. If the calculation result is bigger than 0, post result to aggregator

StringCalculator - Aggregeringsservice

© Creuna

Page 47: Creuna TDD workshop

• 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

Page 48: Creuna TDD workshop

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

Page 49: Creuna TDD workshop

GOD sommer!