Introduksjon til Unit Testing

Enhetstesting er relativt ny for ActionScript-prosjekter. Selv om FlexUnit har eksistert en stund, var det ikke intuitivt å sette opp og det var mange inkonsekvenser med dokumentasjonen. Heldig for oss, er FlexUnit nå innebygd i Flash Builder 4. Selv om dokumentasjonen fortsatt er sparsom, vil denne opplæringen være en god grunn for å sette opp en Test Suite, gå over flere eksempler på enhetstest og vise hvordan å kjøre / analysere dem.

For de som ikke er kjent med enhetstesting, la oss se hva Wikipedia har å si

I dataprogrammering er enhetstesting en programvareverifikasjons- og valideringsmetode der programmereren får tillit til at individuelle kildekodenheter er egnet for bruk ... Enhetstester skrives vanligvis og drives av programvareutviklere for å sikre at koden oppfyller sin design og oppfører seg som beregnet . - wikipedia

I denne opplæringen vil jeg vise deg hvordan jeg satte opp noen enkle enhetstester på min Flash Camo-rammeverk. Du må laste ned en kopi av Flash Builder 4 (i Beta akkurat nå) for å følge med. Også, du vil laste ned den nyeste versjonen av Flash Camo (2.2.1) herfra.

Trinn 1: Konfigurere et Unit Test Project

La oss lage et nytt prosjekt som heter UnitTestIntro.

Vi må plassere vår Flash Camo SWC i en libs / swcs mappe inne i prosjektet vårt:

Til slutt må vi fortelle prosjektet vårt hvor du kan finne vår SWC, høyreklikk på prosjektet og gå inn i egenskapene. Gå til ActionScript-byggepanen og velg fanen Bibliotekspass. Klikk på Legg til SWC-mappe og pek den til lib / swcs-katalogen.

Nå som vi har alt oppsett, kan vi begynne å gjøre noen grunnleggende enhetstesting. Det er viktig å merke seg at du ikke kan gjøre enhetstesting direkte i et Flex Library-prosjekt. Det er ikke et problem for dette prosjektet, men hvis du vil teste et bibliotek med kode som jeg vanligvis gjør, er det satt opp et nytt prosjekt (som vi gjør her), så knytt de to prosjektene sammen og opprett alle tester i det nye prosjektet.

Hvis du ikke jobber i et Flex Library-prosjekt og vil teste koden din, kan du bare lage tester i samme prosjekt. Jeg vil foreslå å holde de to separate, på denne måten kan du tydelig se hva som er testklasser og hva er ekte klasser. Vi kommer inn på dette litt senere når du ser hvordan vi setter opp testen.

Trinn 2: Utarbeide en plan

Før jeg starter noe, tar jeg et øyeblikk for å finne ut nøyaktig hva jeg skal gjøre. Dette er svært kritisk når du setter opp enhetstester. Denne typen utvikling kalles Testdrevet utvikling. Jeg tror jeg ser en annen definisjon som kommer opp:

Testdrevet utvikling (TDD) er en programvareutviklingsteknikk som bruker korte utviklingshererasjoner basert på forhåndskrevne testtilfeller som definerer ønskede forbedringer eller nye funksjoner. Hver iterasjon produserer kode som er nødvendig for å passere det iterasjonens tester. Endelig reflekterer programmereren eller teamet koden for å imøtekomme endringer. Et sentralt TDD-konsept er at å forberede tester før koding letter hurtig tilbakemelding. - wikipedia

Siden dette er en kort intro, skal vi bruke et eksisterende kodebibliotek for å teste mot. Men når du bygger din egen applikasjon, bør du skrive tester underveis for å validere at koden fungerer, og at eventuelle endringer / refactoring ikke bryter kodens implementering. Her er en oversikt over testene vi skal utføre:

  • Opprett en forekomst av et CamoPropertySheet.
  • Bekreft at den kan analysere CSS.
  • Test antall selektorer som ble funnet.
  • Test at CamoPropertySheet kan konverteres tilbake til en streng.
  • Test hva som skjer når vi ber om en velger som ikke ble funnet.
  • Bekreft rydding av et CamoPropertySheet.

Hvis du er ny i Flash Camo, kan du sjekke inn introen jeg skrev (del 1 og del 2), men du kan enkelt gjøre denne opplæringen uten kjennskap til hvordan rammen fungerer. Igjen, dette er bare å være et kodebibliotek for oss å teste med.

Trinn 3: Opprette vår første test

Nå som vi har en plan for å gjøre testingen, la oss lage vår første test. Høyreklikk på prosjektet ditt og velg Ny> Testcase klasse

Du vil nå bli presentert med opprettelsesveiviseren. Det bør være kjent for alle som har skapt en klasse i Flex / Flash Builder før. Her ser du hvordan vinduet ser ut:

La oss snakke om noen av de nye feltene i veiviseren. Vi kan starte med at Superclass allerede er fylt ut for oss: flexunit.framework.TestCase. Du kan ikke endre dette og sannsynligvis burde ikke. Alt dette gjøres, er å forlenge basetestklassen fra Unit Test Framework. Deretter ser du noen avkrysningsbokser for kodegenerering. La alle disse være merket som standard. Til slutt er det et felt for klassen vi vil teste.

Siden vi skal teste Flash Camos CamoPropertySheet, la oss fylle følgende verdier i skjemaet:

 Navn: CamoPropertySheetTest klasse for å teste: camo.core.property.CamoPropertySheet

Her er et skjermbilde av hvordan jeg setter opp dette:

Hit slutt og vi bør ha vår første test klar for oss å legge til noe kode til.

Trinn 4: Anatomi av en TestCase klasse

La oss ta en titt på koden Flash Builder har generert for oss:

Vi starter med å ha en privat eiendom kalt classToTestRef som er satt til verdien av vår CamoPropertySheet. Dette gjør at testen kan skape en forekomst av denne klassen og tvinger kompilatoren til å importere den når vi driver testen vår.

Den neste viktige metoden er Setup. Det er her vi skal lage en forekomst av testklassen, konfigurere den og sørge for at alt er klart for oss å utføre en test.

Den siste metoden her er rive ned. Dette er hvor vi vil ødelegge testkursens forekomst når testen er fullført. Dette er svært viktig når du kjører flere tester.

Du har kanskje lagt merke til i slutten av klassen er det en annen metode som kalles testSampleMethod som er kommentert. Dette er et eksempel på hvordan du vil sette opp en enkelt test.

Hver test vil være en metode vi legger til i denne klassen. Når vi kjører Unit Test Harness, kaller det automatisk alle våre metoder dynamisk, selvfølgelig starter med setUP og etterbehandling med rive ned.

Nå som vi har en grunnleggende forståelse av TestClass-oppsettet, la oss se på å kjøre den.

Trinn 5: Kjører enhetstesten

Før vi kan kjøre dette, trenger vi minst én test. La oss ikke kommentere testSampleMethod for dette eksempelet.

Når du har uncommented the testSampleMethod la oss høyreklikke på prosjektet vårt og velg Kjør som> Utfør FlexUnit Test.

Du bør nå se følgende vindu som ber oss om å velge hvilken test vi vil kjøre.

Som du ser er dette satt opp for når vi har mye å teste, men for nå har vi bare en testSampleMethod å kjøre. Klikk Velg alt og trykk OK.

Etter at testen er kjørt, vil nettleseren din dukke opp med følgende side:

Hvis du går tilbake til Flash Builder, vil du også se dette i FlexUnit Results-panelet:

Se hvor lett dette skulle løpe? Vi har utført vår første enhetstest, og vi har allerede en enkelt feil. Før vi fortsetter å fikse denne feilen, kan vi snakke om disse to vinduene.

Nettstedet som var åpent, skal automatisk lukke, men noen ganger gjør det ikke. Dette er en enkel swf som utfører våre tester i FLASH og utdataer noen data Flash Builder leser for å vise til de endelige resultatene av testen. Du kan ignorere denne nettsiden for det meste.

FlexUnit Results-panelet er der alle resultatene vises, samt et sted som lar deg organisere og filtrere test tilbakemelding. Vi går over dette litt senere i opplæringen når vi faktisk har noe å teste.

Trinn 6: Oppsett

Før vi virkelig kan komme inn i testing, må vi sette opp testklassen vår. la oss legge til følgende kode i Setup metode:

 var xml: XML =  ; rawCSS = xml.toString (); ark = nytt CamoPropertySheet (); sheet.parseCSS (rawCSS);

Vi må også sette opp noen egenskaper:

 privat var ark: CamoPropertySheet; private var rawCSS: String;

Her er hva som skjer i dette oppsettet: For at vi skal teste CamoPropertySheet, må vi trenge litt CSS som en streng. Normalt vil jeg laste inn CSS fra en ekstern fil, men siden vi gjør en enkel test, oppretter jeg bare en ny XML-blokk og legger CSS-teksten inni den første noden. Normalt behøver du ikke å pakke inn CSS for CamoPropertySheet inne i XML, men når du arbeider med store strenge inne i editoren, finner jeg det lettere å bruke xml siden du kan pakke inn teksten og den beholder noe formatering.

Deretter ser du at vi setter vår rawCSS-egenskap til XML-strengens verdi. Dette konverterer xml til en streng. Deretter oppretter vi et nytt CamoPropertySheet. Til slutt forteller vi arket for å analysere rawCSS.

Det er alt som er å sette opp denne klassen. Oppsettet er forskjellig for hver klasse du tester. Det er viktig å demonstrere at vi gjør det minste minimum for å få en klasse klar til å bli testet, og vi kan ikke teste en klasse uten verdier kan vi?

Trinn 7: Vår første test

La oss få rett på det. Når en CamoPropertySheet har analysert en css-streng, kan vi be om en rekke Selector-navn for å bekrefte at alt faktisk har blitt analysert. For de som ikke er kjent med CSS-jargong, er en velger navnet på en css-stil, dvs. baseStyle ... ville ha en selector kalt baseStyle.

Her er hva vår test vil se ut på engelsk:

  1. Få en liste over selektorer fra CamoPropertySheet.
  2. Få lengden på selectoren.
  3. Sammenlign lengdeverdien til 6 (tallet vi forventer returnert).

La oss erstatte vår testSampleMethod med følgende metode:

 offentlig funksjon testParseCSS (): void var selectors: Array = sheet.selectorNames; var totalt: tall = selectors.length; assertEquals (total, 6); 

Som du kan se får vi en rekke valgnavn. Deretter får vi totalt og introduserer vår første test assetEquals. I neste trinn vil jeg forklare assertMethods mer detaljert, men la oss bare kjøre dette og se om testen passerer.

Når du kjører testen, bør du se følgende i FlexUnit Results-panelet:

Fint, vår test bestått. Vi mottok det eksakte antall selektorer som vi ventet. La oss se på hvilke påstandstester vi kan bruke.

Trinn 8: Påstander

I enhetstesting kjører vi påstander. Hvert påstand håndterer en bestemt type test. Her er en kort oversikt over de vanligste påstandene du sannsynligvis vil bruke:

  • assertEquals - test for å se om en verdi er lik en annen.
  • assertFalse - test for å se om verdien er lik false.
  • assertNotNull - test for å se om verdien ikke er lik null.
  • assertNotUndefined - test hvis verdien ikke er udefinert.
  • assertNull - test hvis verdien er null.
  • assertStrictlyEquals - test for å se om to verdier er strengt lik hverandre.
  • assertTrue - test for å se om verdien er sant.
  • assertUndefined - test for å se om verdien er udefinert.

Nå, før vi tester et eksempel på hver, la vi sette opp vår rive ned metode.

Trinn 9: Riv ned

Dette kommer til å være et veldig kort skritt, men det er en veldig viktig en. La oss legge til følgende linje i vår rive ned metode etter super.tearDown ():

 ark = null;

Hva dette i utgangspunktet gjør er å fjerne referansen til vår CamoPropertySheet slik at søppelsamleren kan fjerne den.

Du bør alltid sette opp din rive ned spesielt når du kjører flere testklasser eller en stor testpakke.

Trinn 10: Assert Equals

Vi har allerede sett et eksempel på dette før i trinn 7, men la oss gå gjennom og legge til en annen assertEquals. Her er neste test vi skal utføre:

  1. Komprimer CSS-tekst (fjern hvite mellomrom, spesialtegn og andre hindringer som css-parseren kanskje ikke kan gjenkjenne) siden CamoPropertySheet automatisk komprimerer css-test når den analyseres.
  2. Konverter CamoPropertySheet til tekst (dette vil være en komprimert versjon av RawCSS vi brukte tidligere).
  3. Sammenlign at CamoPropertySheet-teksten er lik vår komprimerte css-streng.

For å kjøre testen, la vi legge til følgende metode:

 offentlig funksjon testToString (): void var compressedCSS: String = "baseStyle x: 10; y: 10; bredde: 100; høyde: 100; polstring: 5; margin: 10; baseStyle .Button x: 0; y : 0; bakgrunnsfarge: # 000000; # playButton bakgrunnsfarge: #FFFFFF; bakgrunnsbilde-: url ( '/ bilder / full_screen_background.jpg'); # fullScreenButton bakgrunnsfarge: # FF0000; background- bilde: url ( '/ bilder / full_screen_background.jpg'); # playButton: over bakgrunnsfarge: # 333333; interaktive markør hånd; "; assertEquals (sheet.toString (), komprimertCSS); 

Kjør nå enhetstesten, og kontroller at du velger begge testene i avmerkingsboksene. Nye tester blir ikke automatisk valgt. Hvis alt gikk bra bør du se en suksess, og at 2 tester ble kjørt.

Trinn 11: Assert False

Vi kan gjøre en enkel test for å sikre at hvis vi ber om en selector som ikke eksisterer, får vi en falsk verdi. Slik gjør vi det med CamoPropertySheet:

  1. Lag en forespørsel om en velger som ikke eksisterer.
  2. Kontroller den valgte selgerenes navn for å se om den er lik «EmptySelector» - en konstant på PropertySelector-klassen.
  3. Angi om verdien er feil.

Her er koden for å utføre testen:

 offentlig funksjon testEmptySelector (): void varvelger: PropertySelector = sheet.getSelector ("testSelector"); Var eksisterer: Boolean = (selector.selectorName == PropertySelector.DEFAULT_SELECTOR_NAME)? usann sannhet; assertFalse (finnes); 

Som du kan se, ber vi bare om et falsk stilnavn testSelector. Vi ser etter om selgerens navn er standardnavnet som brukes når ingen velger er funnet. Endelig sender vi den eksisterende variabelen til assertFalse metode. Når du kjører dette, bør du nå se 3 passerer som en suksess.

Trinn 12: Anerkjenn ikke null

Deretter vil vi sørge for at tekstverdien fra vår CamoPropertySheet aldri er null. La oss se på hvordan du skal strukturere vår test:

  1. anrop toString på vår CamoPropertySheets-forekomst og test for å se om det ikke er null

Her er vår testmetode:

 offentlig funksjon testCSSValue (): void assertNotNull (sheet.toString ()); 

Dette er ganske rett fram, så når du kjører testen, burde vi nå ha 5 suksesser. Hver gang vi kjører testen, kan vi sjekke for å se navnene på metodetestene våre ved å klikke på Standard Suite-mappen vår FlexUnit Results Panel tilbake i Flash Builder.

Trinn 13: Anerkjenn ikke udefinert

I denne neste testen skal vi følge opp den tomme veltestesten for å verifisere at hver velger har en selectorName.

  1. Få en velger som ikke eksisterer.
  2. Få en velger som eksisterer.
  3. Test for å se om begge velgerens navn ikke er definert.

Her er testmetoden:

 offentlig funksjon testSelektorerHaveNames (): void varselectorA: String = sheet.getSelector ("testSelector"). selectorName; var selectorB: String = sheet.getSelector ("baseStyle"). selectorName; assertNotUdedefined (selectorA, selectorB); 

De to første linjene er selvforklarende; vi ber bare om to seleksorer og en av dem vi vet eksisterer ikke. Når vi gjør påstanden, skjønner du imidlertid at vi passerer i to verdier i stedet for den normale vi har gjort opp til dette punktet. Dette er ikke et unikt eksempel, faktisk kan hver av assert metodene passere deg i et hvilket som helst antall verdier som skal testes. Her sørger vi bare for at selectorA og selectorB ikke er udefinert.

Trinn 14: Assert Strictly Equals

Her er et eksempel på hvordan du strengt kan sammenligne to objekter. Her bruker jeg strenge som kanskje ikke er den beste bruken av dette eksempelet, men det er godt å se testen i aksjon. Hva skal vi gjøre?

  1. Klon CamoPropertySheet.
  2. Test at strengverdien av CamoPropertySheet er lik verdien av en klonet CamoPropertySheet.
 offentlig funksjon testClone (): void var klone: ​​CamoPropertySheet = sheet.clone () som CamoPropertySheet; assertStrictlyEquals (sheet.toString (), clone.toString ()); 

Som du kan se, kaller vi klonmetoden til CamoPropertySheet for å få tilbake en eksakt kopi av PropertySheet. Neste kjører vi det gjennom påstandstesten ved å ringe toString metode på hver. Hvis den returnerte CSS-testen er den samme, har vi en suksess for testen.

Trinn 15: Sann True

Nå vil vi teste at når vi ber om en velger, har den en eiendom vi forventer. Her er testen:

  1. Be om baseStyle velger.
  2. Test for å se om selgeren har eiendommen x.

Her er testmetoden:

 offentlig funksjon testSelectorHasProperty (): void varvelger: PropertySelector = sheet.getSelector ("baseStyle"); assertTrue (selector.hasOwnProperty ( "X")); 

Som du kan se her, forventer vi vår baseStyle selector for å ha x-egenskapen. Hvis dette eksisterer, kan vi anta at den ble korrekt analysert fra CSS-strengen. Siden det eksisterer har vi bestått denne testen.

Hver av disse testene blir selvforklaring på hvordan du implementerer dem. La oss se på hva som skjer når vi feiler en test i de neste to trinnene.

Trinn 16: Angi Udefinert

Vi skal teste for udefinerte nå, men Flash Camo er designet for ikke å returnere udefinert. Så følgende test vil mislykkes. La oss sjekke ut hva vi skal teste for.

  1. Ring den klare metoden på CamoPropertySheet.
  2. Test for å se om du ringer toString vil returnere udefinert.

Her er koden for testen:

 public function testClear (): void sheet.clear (); assertUndefined (sheet.toString ()); 

La oss nå kjøre denne testen og gå videre til neste trinn for å diskutere resultatene.

Trinn 17: Mislykkes en test

Hvis du gjorde det forrige trinnet og kjørte enhetstesten, bør du se følgende i FlexUnit Results-panelet:

Legg merke til hvordan vi har 1 feil fra vår testClear metode?

Hvis du dobbeltklikker på den mislykkede testen i testresultatpanelet, hopper du til kilden til testen som mislyktes. Dette er en fin måte å korrigere feilen din på eller endre testen, slik at den ikke mislykkes. Det er ikke mye mer å feile en test da dette. Hver test som feiler vil dukke opp i dette panelet, kan du fortelle at panelet bare viser mislykkede tester ved å klikke på det røde utropstegnet over hvor det forteller deg hvor mange feil du hadde.

Nå som vi har mislyktes, erstatter denne testen den med følgende:

 public function testClear (): void sheet.clear (); assertEquals (sheet.toString (), ""); 

Hvis du kjører testen igjen, vil du se at den vil passere. Nå har du 7 av 7 bestått tester, og denne klassen har vellykket arbeid. La oss snakke om å sette opp enhetstester for dine egne tilpassede klasser.

Trinn 18: Auto Generating Test Classes

Frem til dette punktet har vi testet et forkompilert bibliotek, men du kan være interessert i hvordan dette vil fungere på dine egne klasser. Vi skal endre doc-klassen litt og deretter kjøre en tilpasset enhetstest på den. For å komme i gang, erstatt all koden i UnitTestIntro-klassen med følgende:

 pakke import flash.display.Sprite; offentlig klasse UnitTestIntro utvider Sprite private var _firstName: String; privat var _lastName: String; privat var _loggedIn: boolsk; offentlig funksjon UnitTestIntro () _firstName = "Jesse"; _lastName = "Freeman";  offentlig funksjon få firstName (): String return _firstName;  offentlig funksjon få lastnavn (): String return _lastName;  offentlig funksjon isLoggedIn (): Boolean return _loggedIn; 

Når du har koden på plass, høyreklikk på UnitTestIntro og velg Ny> Testcase klasse. Hvis du ser på veiviseren denne gangen vil du se at alle feltene er fylt ut for oss:

Denne gangen, i stedet for å klikke Fullfør, treffer du neste og ser på følgende vindu:

Her kan du velge alle offentlige metoder for denne klassen for å teste. Legg merke til hvordan våre getters for firstName og lastname ikke er en del av denne listen. Enhetstesting kan bare utføres på offentlige metoder. Også, du vil se hver arvelig metode i klassen, så vi har Sprite / DisplayObject-metoder her siden vår doc-klasse utvider Sprite. Å velge isLoggedIn og slå ferdig.

Hvis du ruller ned til bunnen av den nye testklassen som nettopp ble generert, vil du se at den automatisk har lagt til i en testmetode for isLoggedIn.

Når du tester din egen kode, kan Flash Builder bidra til å automatisere prosessen med stillasettene dine. Dette er en stor hjelp når det gjelder store klasser som har mange metoder.

Trinn 19: Best Practices

Nå skal du ha en solid forståelse av hvordan Unit Testing i Flash Builder fungerer. Du kan til og med være klar til å begynne å sette opp din egen test. Det er mange ting jeg ikke kunne dekke i denne korte opplæringen, så her er noen ting å huske på når du lager tester.

  • Hold koden liten og lett testbar. Lag korte metoder, bryk kode ned i "enheter" for å bidra til å lette testingen. Det er greit å ha mange metoder i klassene dine. Ikke bare hjelper det deg når enhetsprøving, men også når du utvider klasser og håndterer arv overordnet.
  • Test en oppførsel og ikke en metode. Denne opplæringen viste deg hvordan jeg ville samhandle med forekomsten av CamoPropertySheet. Jeg prøvde atferdsresponser for det underliggende parsing / retrieval-systemet. Pass på at du ikke tester disse funksjonene, og returnerer bare verdier, men at den underliggende logikken er riktig. Gjorde noe blitt analysert, gjorde de avhengige metodene hva de forventet å gjøre?
  • Hold testnavnene rene. Du bør kunne forstå hva som foregår ved å bare se på testmetodenes navn. Husk at denne koden ikke er kompilert i den endelige søknaden din, så hvis du har utrolig lange metodenavn, er det ok så lenge de er beskrivende.
  • Ikke stole på konsollvinduet for testen din. Dette betyr at du ikke bør forvente at en utvikler skal se sporutganger for å se om testen fungerer som den skal. I stedet gjør testen feil eller lykkes, og ikke utdataene sine resultater.
  • Gjør et søk på Unit Testing på andre språk for å se hvordan det er implementert andre steder. Ta også opp en bok om testdrevet utvikling (TDD).

Konklusjon

Som du kan se, er det enkelt å sette opp Unit Testing, men å skape applikasjoner som roterer rundt Test Driven Development er en kunstform i seg selv. Forhåpentligvis etter dette introet vil du være komfortabel å sette opp en enkel test for å validere at koden fungerer som forventet. Som du stole mer og mer på Unit testing, vil antall feil i koden din gå dramatisk ned. Så lenge du husker å kode mot å bestå en test, holder metodene dine små og validerer enhetstestene dine ofte, vil du være godt på vei til å bygge mer stabil kode.

Takk for at du leste.