Ingen vill skicka buggysoftware. Att säkerställa att du släpper ut en mobilapplikation av högsta kvalitet kräver mycket mer än en humanstyrd manuell kvalitetssäkring. Nya enheter och operativsystem släpps ut till allmänheten varje år. Det innebär att det finns en ständigt växande kombination av skärmstorlekar och operativsystemversioner där du måste testa din mobilapplikation. Inte bara skulle det vara extremt tidskrävande, men försök att testa din iOS-applikation med manuell provning försummar en hel del av den moderna mjukvaruutvecklingsprocessen, automatiserad kvalitetssäkringstestning.
I dagens värld finns det många verktyg som kan användas för att automatiskt testa programvaran du skriver. Några av dessa verktyg upprätthålls genom en öppen källmodell, men det finns också en kärnuppsättning som tillhandahålls av Apple. Med varje ny version av iOS SDK har Apple fortsatt att visa sitt engagemang för att förbättra verktygen som finns tillgängliga för utvecklare för att testa koden som de skriver. För IOS-utvecklaren som är ny för automatiserad testning och intresserad av att komma igång, är Apples verktyg ett bra ställe att börja.
Denna handledning kommer att ge instruktioner för att använda ett verktyg som Apple tillhandahåller för automatisk testning, XCTest. XCTest är Apples enhetstestramar. Enhetstestning är typen av automatiserad testning som verifierar kod på lägsta nivå. Du skriver Objektiv-C-kod som kallar metoder från din "produktion" -kod och verifierar att koden som testet verkligen gör vad den är avsedd att göra. Är variablerna rätt inställda? Är returvärdet korrekt?
Test som skrivs med XCTest-ramen kan utföras gentemot din ansökans kod för att hjälpa dig att få förtroende för att du skapar en buggfri produkt, eftersom nya kodändringar inte bryter mot befintlig funktionalitet.
Som standard skapas varje nytt Xcode-projekt med en bra utgångspunkt för att skriva enhetstester. Detta inkluderar tre saker:
Låt oss gräva i strukturen för ett iOS-enhetstest. Ett individuellt enhetstest representeras som en enda metod inom något underklass av XCTestCase
där metoden återvänder ogiltig
, tar inga parametrar, och metodnamnet börjar med testa
.
- (void) testSomething
Lyckligtvis gör Xcode att skapa testfall enkelt. Med nya Xcode-projekt skapas ett första testfall för dig i en separat filgrupp vars namn suffixas av ordet tester.
Jag har skapat ett provprojekt som kan användas som referens för exemplen i denna handledning. Ladda ner projektet från GitHub och öppna det i Xcode.
I urvalsprojektet hittar du gruppen test i mappen som heter JumblifyTests.
För att skapa ditt första testfall högerklickar du på filgruppen, JumblifyTests, och välj Ny fil. Välja Testfallsklass från iOS> Källa avsnitt och ge den nya underklassen ett namn.
Den typiska namngivningskonventionen är att namnge testfallet så att det är namnet på den motsvarande klassen som testas, suffixad med tester. Eftersom vi ska testa JumblifyViewController
klass, namnge XCTestCase
underklass JumblifyViewControllerTests
.
I den helt nya XCTestCase
underklass, ser du fyra metoder. Två av dessa är prov själva. Kan du identifiera vilka de är? Kom ihåg att testmetodnamn börjar med ordet "test".
Om du inte bestämde dig för det, är de testmetoder som skapats som standard testExample
och testPerformanceExample
.
Ta bort båda testen, för vi ska skriva vårt från början. De andra två metoderna, inrätta
och riva ner
, överrätts från superklassen, XCTestCase
. De är unika i det inrätta
och riva ner
kallas före och efter varje testmetod åberopas respektive. De är användbara platser för centralisering av kod som ska utföras före eller efter varje testmetod heter. Uppgifter som vanlig initiering eller uppringning går här.
Importera huvudfilen till JumblifyViewController
klass och lägg till en egenskap av typ JumblifyViewController
till XCTestCase
underklass.
@property (nonatomic) JumblifyViewController * vcToTest;
I inrätta
metod, initiera egenskapen som visas nedan.
- (void) setUp [super setUp]; self.vcToTest = [[JumblifyViewController alloc] init];
Vi ska nu skriva ett test för att testa reverseString:
metod för JumblifyViewController
klass.
Skapa en testmetod som använder instantiated vcToTest
motsätta sig att testa reverseString:
metod. I denna testmetod skapar vi en NSString
objekta och vidarebefordra den till bildkontrollen reverseString:
metod. Det är vanligt att ge ditt test ett meningsfullt namn för att klargöra vad testet testar.
- (void) testReverseString NSString * originalString = @ "himynameisandy"; NSString * reversedString = [self.vcToTest reverseString: originalString];
Vid det här laget har vi inte gjort någonting användbart ändå, för vi har inte testat reverseString:
metod än. Vad vi behöver göra är att jämföra produktionen av reverseString:
metod med vad vi förväntar oss att produktionen ska vara.
De XCTAssertEqualObjects
funktionen är en del av XCTest-ramen. XCTest-ramen tillhandahåller många andra metoder för att göra påståenden om applikationstillstånd, såsom variabel jämställdhet eller booleska uttryck. I det här fallet har vi sagt att två objekt måste vara lika. Om de är, passerar testet och om de inte är, misslyckas testet. Ta en titt på Apples dokumentation för en omfattande lista över påståenden från XCTest-ramen.
- (void) testReverseString NSString * originalString = @ "himynameisandy"; NSString * reversedString = [self.vcToTest reverseString: originalString]; NSString * expectedReversedString = @ "ydnasiemanymih"; XCTAssertEqualObjects (expectedReversedString, reversedString, @ "Den omvända strängen matchade inte förväntad omvänd");
Om du försöker kompilera koden vid denna punkt kommer du att märka en varning när du försöker ringa reverseString:
från testfallet. De reverseString:
Metod är en privat metod för JumblifyViewController
klass. Det betyder att andra objekt inte kan åberopa denna metod eftersom den inte är definierad i huvudfilerna i JumblifyViewController
klass.
Medan du skriver testbar kod är en mantra som många utvecklare följer, vill vi inte onödigt ändra vår kod under test. Men hur kallar vi det privata reverseString:
metod för JumblifyViewController
klass i våra test? Vi kan lägga till en offentlig definition av reverseString:
metod för huvudfilen till JumblifyViewController
klass, men det bryter inkapslingsmönstret.
En lösning är att lägga till en privat kategori på JumblifyViewController
klass för att avslöja reverseString:
metod. Vi lägger till den här kategorin i XCTestCase
underklass, vilket innebär att den endast är tillgänglig i den klassen. Genom att lägga till den här kategorin kommer testfallet att kompileras utan varningar eller fel.
@interface JumblifyViewController (Test) - (NSString *) reverseString: (NSString *) stringToReverse; @slutet
Låt oss köra våra tester för att se till att de passerar. Det finns flera sätt att köra enhetsprov för en iOS-applikation. Jag är en genvägsnyckel för tangentbord, så min mest använda teknik för att köra min enhetstester för min ansökan är genom att trycka på Kommando-U. Denna tangentbordsgenväg kommer att köra alla tester för din ansökan. Du kan också utföra samma åtgärd genom att välja Testa från Produkt meny.
När din testpaket växer, eller om du gillar implementera testdriven utveckling, kommer du att upptäcka att du kan bli för tidskrävande att köra din testpaket. Eller det kan komma i vägen för ditt arbetsflöde. Ett mycket användbart kommando, begravd inom Xcodes meny, som jag har blivit kär i är Command-Option-Control-U. Den här genvägen utlöser ett kommando som kör testet som markören befinner sig i. När du har testats ut och slutförts, bör du alltid köra hela testpaketet. Att köra ett individuellt test är användbart när du skriver ett nytt testtest eller när du felsöker ett fel test.
Kommandot att köra ett test kompletteras med Kommando-alternativ-Control-G, vilket återger den sista testkörningen. Det här kan vara hela testpaketet eller bara det senaste testet du arbetar med. Det är också användbart om du har navigerat bort från vilket test du arbetar med och du är fortfarande i färd med att felsöka det.
Du kan se dina testresultat på ett par ställen. En av dessa platser är Test Navigator till höger.
Ett annat alternativ är att titta på rännan på Källeditor.
På någon av dessa två ställen kommer att klicka på den gröna diamanten med det vita väljmärket att återställa det specifika testet. I händelse av ett misslyckat test ser du en röd diamant med ett vitt kors i mitten. Om du klickar på det kommer du också att återuppta det specifika testet.
Xcode 6 introducerade två nya spännande tillägg till enhetstestning på IOS och OS X, testning av asynkron funktionalitet och mätning av prestanda för ett visst kodstycke.
Före Xcode 6 fanns det inget bra sätt att enhetstest asynkron kod. Om din enhetstest kallade en metod som innehöll asynkron logik kunde du inte verifiera den asynkrona logiken. Testet skulle slutföra innan den asynkrona logiken i testmetoden utfördes.
För att testa asynkron kod har Apple introducerat ett API som tillåter utvecklare att definiera en förväntan som måste uppfyllas för att testet ska slutföras framgångsrikt. Flödet är enligt följande, definiera en förväntan, vänta tills förväntan är uppfylld och uppfylla förväntningarna när den asynkrona koden har slutförts. Ta en titt på nedanstående exempel för att förtydliga.
- (void) testDoSomethingThatTakesSomeTime XCTestExpectation * completionExpectation = [självförväntningWithDescription: @ "Long method"]; [self.vcToTest doSomethingThatTakesSomeTimesWithCompletionBlock: ^ (NSString * resultat) XCTAssertEqualObjects (@ "result", result, @ "Resultatet var inte korrekt!"); [completionExpectation fulfill]; ]; [self waitForExpectationsWithTimeout: 5.0 handler: nil];
I det här exemplet testar vi doSomethingThatTakesSomeTimesWithCompletionBlock
metod. Vi vill leda till framgång eller misslyckande av vårt test på värdet som returneras i färdigställningsblocket som kallas med den metod som testas.
För att göra detta definierar vi en förväntan i början av testmetoden. Vid slutet av testmetoden väntar vi på att förväntan ska uppfyllas. Som du kan se kan vi också passera i en timeout-parameter.
Den faktiska påståendet av testet görs inom färdigställningsblocket för den metod som testas där vi också uppfyller förväntan som vi definierade tidigare. Som ett resultat, när testet körs, väntar testet tills förväntan är uppfylld eller det misslyckas om tidsgränsen löper ut och förväntan inte är uppfylld.
Ett annat tillägg till enhetstestning i Xcode 6 är förmågan att mäta prestanda för en bit kod. Detta gör det möjligt för utvecklare att få insikt i den specifika tidsinformationen för koden som testas.
Med prestandatest kan du svara på frågan "Vad är den genomsnittliga tiden för körning för den här koden?" Om det finns en sektion som är särskilt känslig för förändringar när det gäller den tid det tar att utföra, kan du använda prestandatestning för att mäta hur lång tid det tar att utföra.
Du kan också definiera en exekveringstid för baslinjen. Det betyder att om koden som testas avviker väsentligt från den baslinjen, misslyckas testet. Xcode kommer upprepade gånger att köra koden som testas och mäta dess exekveringstid. För att mäta prestanda för ett stycke kod, använd measureBlock:
API som visas nedan.
- (void) testPerformanceReverseString NSString * originalString = @ "himynameisandy"; [self measureBlock: ^ [self.vcToTest reverseString: originalString]; ];
Klicka på informationsmeddelandet som visas.
Ange eller ändra baslinjetiden för körning för prestandatestet.
I den här handledningen har du lärt dig hur du använder Xcode för att skapa enhetstester för att verifiera en iOS-applikation på ett programmatiskt och automatiserat sätt. Ge det ett försök, antingen på en befintlig kodbas eller något helt nytt. Oavsett om du gör ett fullständigt engagemang för enhetstestning eller lägger till några test här och där, lägger du bara till ett värde för ditt projekt genom att skriva mer starkt verifierad programvara som är mindre benägen att bryta mot framtida förändringar. Enhetstestning är bara början på automatiserad programvarutestning. Det finns flera ytterligare lager av test som du kan lägga till i ett iOS-program.