SWT - Design for Testability Flashcards
Hvad forståes ved en komponents dependencies/afhængigheder?
En komponent (f.eks. en klasse) indgår ofte som en del af et større system, hvor den interagerer med andre dele af systemet. Disse andre dele, som klassen interagerer med, kaldes for klassen dependencies/afhængigheder.
Hvad skal vi være opmærksomme på, hvis vi tester nedenstående klasse A?
At methodA() kalder videre til klasse B, så hvis testen fejler, ved vi ikke om fejlen opstår i klasse A eller klasse B.
Derfor er vi nødt til at afkoble den klasse, som vi tester, fra resten af systemet.
Hvad er Comple Test vs. Robust Tests en balancegang imellem?
- Hvis vi ved hvad der er indeni vores unit, kan vi bedre teste det
- Hvis vi kan kigge indeni vores unit, kan vi lavere mere komplette tests
VS
- Hvis vi baserer vores tests på hvad der er indeni vores unit, kan testen breake når vores kode ændres/vedligeholdes
Hvad er Black Box testing?
En måde at teste funktionalitet/behavior på, når vi ikke kender til hvad der foregår indeni i den kode (unit) som vi skal teste. Dvs. vi ser kun på hvad der sker i overfladen af ‘den sorte box’ og hvad der sker udadtil.
Hvad er White Box testing?
Hvordan kan man lave en Black Box test?
-
ACT:
- Give et input/act’e (f.eks. at forsøge at kalde noget på den) og så observere på outputtet (f.eks. om den kalder videre i systemet eller noget andet)
-
INTERACT:
- Kalder noget på den, som giver en returværdi, som vi så observerer på
-
REACT:
- Kalder noget på den, som kalder ivdere i systemet og så giver returværdi tilbage til vores objekt (uut), som vi så observerer på
Hvornår ved vi generalt at en Black Box test er sikker/fungerer fornuftigt?
Så længe vi kun bruger den kontrakt, som vi har opsat for vores enhed, kan vi være sikre på at vores tests fungerer fornuftigt.
Med andre ord: Så længe interfacet for uut og interfacet for den testede kode er det samme, er vores tests sikre.
Vil vi helst have Whitebox eller Blackbox tests?
Blackbox tests, da de er lettere at automatisere og testen kan lettere breake ved Whitebox testing, når vi maintainer eller ændre i vores kode senere hen (som vi hele tiden gør som udviklere)
Hvad afgører om vi skal bruge Blackbox eller Whitebox testing?
Hvor meget information vi har om den komponent som vi tester. Vi kan ikke lave Whitebox test, hvis vi ikke kender til hvad der sker indeni koden. I praksis vil vi i kurset helst bruge Blackbox tests.
Vi ønsker at teste funktionaliteten af en klasse. Hvad skal vi gøre først, hvis klassen har dependencies?
Først skal vi afkoble klassen fra resten af systemet som det intereagerer med. På denne måde kan vi kontrollere hvilke dependencies som UUT bruger, f.eks. vores “fake” version af afhængighederne
Hvad vil det sige at vi kontrollere UUT’s dependencies?
At vi kontrollere hvilke afhængigheder som UUT bruger, f.eks. fake dependencies eller rigtige dependencies.
Hvordan kan vi kontrollere typerne af en UUT’s dependencies?
Ved at injecte (vores fake) dependencies ind i UUT, fremfor at klassen selv konstruere det.
På denne måde kan vi isolere UUT fra resten af systemet.
Hvilke steps ligger der i kontrol af dependencies (III eller Triple-I)?
- IDENTIFY: Identificér de eksterne dependencies
- INTERFACE: Introducer et interface til afhængigheden
- INJECT: Erstat (inject) afhængigheden
Hvad kendetegner et interface?
- Kan ikke indeholde fields (variabler)
- Kan kun indeholde function declarations, men funktionernerne defineres kun af de klasser, der implementerer interfacet
- Funktionerne skal erklæres public, når de implementeres i klasserne, der implementerer interfacet
Hvordan kan vi løsne koblingen imellem en klasse og dens dependencies?
Ved at introducere et interface til afhængighederne.
Vi skal introducere et interface til afhængigheden Bedroom. Hvad vil House egentlig have at gøre med Bedroom?
“Kalde TurnLightOff() på sit Bedroom-objektet”
eller
“Slukke lyset i Bedroom” (korrekt)
Hvordan bruges “constructor injection” på dette eksempel?
Få klassen til at anvende interfaces som dens afhængigheder, så den er ligeglad med den konkrete type.
Så fremfor at klassen selv konstruere sine afhængigheder, kan vi injecte hhv. vores fake dependencies eller rigtige dependencies i constructoren for både Produktion og Test-klassen:
Hvordan bruges “property injection” på dette eksempel?
Få klassen til at anvende properties, der sættes i dens constructor, hvor dens dependencies initailiseres.
Disse properties overskrives i Test-klassen, hvor vi injecter vores fake properties.
Hvad kan være et problem ved “property injection”?
At hvis klassen (som vi tester) selv opretter dens dependencies i sin constructor, kan de udføre ting, der ikke kan tilbageføres, selvom vi overskriver dependencies i Test-klassen
Dvs. at vi ikke kan være sikre på vores UUT’s tilstand, når vi tester
Nævn nogle design principper og mønstre for Design for Testability
-
Lav kobling:
- Triple-I (design med interfaces)
- Brug Observer Pattern (i C# oftest gjort med events og delegates)
- Brug Exceptions (men ikke for normal returnering af data)
-
Single responsibility:
- Reducerer antallet af interne tilstande
- Gør koden mere simpel
- Gør det mere simpelt at teste
- Refactor (brug testene for at sikre at du har gjort det rigtigt)
Hvis det er svært at skrive tests, hvad kan det så være symptom på?
- At designet muligvis er dårligt
- At det måske er svært at bruge den unit
- Husk at testen er den første client - hvad med faktiske final client (andre færdige klasser og komponenter)