QUnit, utvecklad av jQuery-teamet, är en utmärkt ram för enhetstestning av JavaScript. I den här handledningen presenterar jag vad QUnit specifikt är och varför du bör bry dig om att du testar din kod noggrant.
QUnit är ett kraftfullt JavaScript-testverktyg som hjälper dig att felsöka kod. Det är skrivet av medlemmar av jQuery-teamet, och är den officiella testpaketet för jQuery. Men QUnit är generellt nog för att testa någon vanlig JavaScript-kod och det kan även testa server-sida JavaScript via någon JavaScript-motor som Rhino eller V8.
Om du inte känner till tanken på "enhetstestning", oroa dig inte. Det är inte för svårt att förstå:
I datorprogrammering är enhetsprovning en mjukvaruverifiering och valideringsmetod där en programmerare testar om enskilda enheter av källkod är lämpliga att använda. En enhet är den minsta testbara delen av en applikation. Vid procedurprogrammering kan en enhet vara en individuell funktion eller procedur.
Detta är citerat från Wikipedia. Enkelt uttryckt skriver du tester för varje funktionalitet av din kod, och om alla dessa tester passeras kan du vara säker på att koden kommer att vara buggfri (för det mesta beror på hur noggrann dina tester är).
Om du inte har skrivit några enhetstester tidigare använder du förmodligen bara din kod till en webbplats direkt, klicka ett tag för att se om något problem uppstår och försök att åtgärda det när du upptäcker ett. Det finns många problem med denna metod.
För det första är det väldigt tråkigt. Att klicka på faktiskt är inte ett enkelt jobb, för du måste se till att allt är klickat och det är mycket troligt att du saknar en sak eller två. För det andra kan allt du gjorde för testning inte återanvändas, vilket betyder att det inte är lätt att hitta regressioner. Vad är en regression? Tänk dig att du skrev en kod och testade den, fixade alla buggar du hittade och publicerade den. Därefter skickar en användare lite feedback om nya fel och begär några nya funktioner. Du går tillbaka till koden, åtgärdar de nya buggarna och lägger till de nya funktionerna. Vad som kan hända är att några av de gamla buggarna kommer igen, som kallas "regressions". Se, nu måste du klicka igen, och chansen är att du inte hittar dessa gamla buggar igen. även om du gör det tar det en stund innan du upptäcker att problemet orsakas av regressioner. Med enhetsprovning skriver du tester för att hitta buggar, och när koden är modifierad, filtrerar du den genom testen igen. Om en regression uppstår, kommer vissa test definitivt att misslyckas, och du kan enkelt fånga dem och veta vilken del av koden som innehåller felet. Eftersom du vet vad du just har ändrat kan det enkelt lösas.
En annan fördel med enhetstestning är speciellt för webbutveckling: det underlättar testningen av kompatibilitet med webbläsare. Kör bara dina tester på olika webbläsare, och om ett problem uppstår i en webbläsare, fixar du det och kör dessa test igen, se till att det inte introducerar regression på andra webbläsare. Du kan vara säker på att alla målbläddrarna stöds, när de alla passerar testen.
Jag skulle vilja nämna en av John Resigs projekt: TestSwarm. Det tar JavaScript-enhetstestning till en ny nivå genom att distribuera den. Det är en webbplats som innehåller många tester, vem som helst kan åka dit, köra några av testerna och sedan returnera resultatet tillbaka till servern. På så sätt kan koden testas på olika webbläsare och till och med olika plattformar verkligen snabbt.
Så hur skriver du enhetstest med QUnit exakt? Först måste du ställa in en testmiljö:
QUnit Test Suite QUnit Test Suite
Som du kan se används här en värdversion av QUnit-ramverket.
Koden som ska testas bör sättas in i myProject.js, och dina test ska införas i myTests.js. För att köra dessa test, öppna helt enkelt denna HTML-fil i en webbläsare. Nu är det dags att skriva några tester.
Byggstenarna i enhetstest är påståenden.
En påstående är ett uttalande som förutser det återstående resultatet av din kod. Om förutsägelsen är falsk har påståendet misslyckats, och du vet att något har gått fel.
För att driva påståenden bör du lägga dem i ett testfall:
// Låt oss testa denna funktionsfunktion isEven (val) return val% 2 === 0; test ('isEven ()', funktion () ok (ärEven (0), 'Noll är ett jämnt tal'); ok (ärEven (2), 'Så är två'); ok , 'Så är negativ fyra'), ok (! Är Even (1), 'En är inte ett jämnt tal'); ok (! Är Even (-7), 'Varken är negativ sju');)
Här definierade vi en funktion, isEven, som upptäcker huruvida ett tal är jämnt, och vi vill testa denna funktion för att se till att det inte returnerar felaktiga svar.
Vi kallar först testet (), som bygger ett testfall Den första parametern är en sträng som kommer att visas i resultatet, och den andra parametern är en återuppringningsfunktion som innehåller våra påståenden. Den här återuppringningsfunktionen kommer att ringas när QUnit körs.
Vi skrev fem påståenden, som alla är booleska. En booleskt påstående förväntar sig att den första parametern är sann. Den andra parametern är också ett meddelande som visas i resultatet.
Här är vad du får när du kör testet:
Eftersom alla dessa påståenden har lyckats gå, kan vi vara ganska säkra på att är jämnt() kommer att fungera som förväntat.
Låt oss se vad som händer om en påstående har misslyckats.
// Låt oss testa denna funktionsfunktion isEven (val) return val% 2 === 0; test ('isEven ()', funktion () ok (ärEven (0), 'Noll är ett jämnt tal'); ok (ärEven (2), 'Så är två'); ok , 'Så är negativ fyra'), ok (! Är Even (1), 'En är inte ett jämnt tal'); ok (! Är Even (-7), 'Varken negativ sju'); // Får ok (3), 'Tre är ett jämnt tal');)
Här är resultatet:
Påståendet har misslyckats eftersom vi medvetet skrev det fel, men i ditt eget projekt, om testet inte passerar, och alla påståenden är korrekta, vet du att en bugg har hittats.
ok () är inte den enda påståendet som QUnit tillhandahåller. Det finns andra typer av påståenden som är användbara vid testning av ditt projekt:
Jämförelseansökningen, equals (), förväntar sig att dess första parameter (vilket är det verkliga värdet) är lika med dess andra parameter (vilket är det förväntade värdet). Det liknar ok (), men matar ut både verkliga och förväntade värden, vilket gör debugging mycket enklare. Gilla ok (), det tar en valfri tredje parameter som ett meddelande som ska visas.
Så istället för:
test ("påståenden", funktion () ok (1 == 1, "en är lika med en");)
Du borde skriva:
test ("påståenden", funktion () lika (1, 1, "en är lika med en");)
Lägg märke till den sista "1", som är jämförelsevärdet.
Och om värdena inte är lika:
test ("påståenden", funktion () lika (2, 1, "en är lika med en");)
Det ger mycket mer information, vilket gör livet mycket enklare.
Jämförelseförklaringen använder "==" för att jämföra dess parametrar, så det hanterar inte array eller objekt jämförelse:
test ("test", funktion () lika (, , misslyckas, det här är olika objekt "), lika med (a: 1, a: 1," misslyckas "); ], [], "misslyckas, det finns olika arrays"), lika med ([1], [1], "misslyckas");)
För att testa denna typ av jämlikhet, ger QUnit en annan slags påstående: identisk påstående.
Identisk påstående, samma (), förväntar sig samma parametrar som likvärdiga (), men det är en djup rekursiv jämförelsehävning som inte bara fungerar på primitiva typer, men också arrays och objekt. Påståenden, i föregående exempel, kommer alla att passera om du ändrar dem till identiska påståenden:
test ("test", funktion () same (, , "passerar, objekt har samma innehåll"), samma (a: 1, a: 1, "pass"); [], [], "passerar, arrays har samma innehåll"), samma ([1], [1], "passerar");)
Observera att samma () använder '===' för att göra jämförelse när det är möjligt, så det kommer att vara till nytta när du jämför speciella värden:
test ('test', funktion () lika (0, false, 'true'), samma (0, false, 'false'), lika (null, odefinierad, 'true'); falskt ");)
Att lägga alla påståenden i ett enda testfall är en riktigt dålig idé, eftersom det är väldigt svårt att upprätthålla och inte ger ett rent resultat. Vad du borde göra är att strukturera dem, sätt dem i olika testfall, var och en syftar till en enda funktionalitet.
Du kan till och med organisera testfall i olika moduler genom att ringa modulfunktionen:
modul ('Modul A'); test ('ett test', funktion () ); test ("ett annat test", funktion () ); modul ('Modul B'); test ('ett test', funktion () ); test ("ett annat test", funktion () );
I tidigare exempel kallas alla påståenden synkront, vilket innebär att de kör varandra efter varandra. I den verkliga världen finns det också många asynkrona funktioner, som ajax-samtal eller funktioner som heter setTimeout () och setInterval (). Hur kan vi testa dessa typer av funktioner? QUnit ger en speciell typ av testfall kallat "asynkront test", vilket är dedikerat till asynkron testning:
Låt oss först försöka skriva det på ett vanligt sätt:
test ('asynkront test', funktion () setTimeout (funktion () ok (sann);, 100))
Se? Det är som om vi inte skrev något påstående. Detta beror på att påståendet sprang asynkront, när det var kallat, var testfallet redan klart.
Här är rätt version:
test ('asynkront test', funktion () // Pausa testet första stoppet (); setTimeout (funktion () ok (sant); // Efter att påståendet har kallats, // fortsätt teststart , 100))
Här använder vi stopp () för att pausa testfallet, och efter att påståendet har ringts, använder vi start () för att fortsätta.
Samtalstopp () omedelbart efter samtalstest () är ganska vanligt; så QUnit ger en genväg: asyncTest (). Du kan skriva om det föregående exemplet så här:
asyncTest ('asynkron test', funktion () // Testet är automatiskt pausat setTimeout (funktion () ok (sant); // Efter att påståendet har kallats, // fortsätt teststart ();, 100 ))
Det finns en sak att se upp för: setTimeout () kommer alltid att ringa sin återuppringningsfunktion, men om det är en anpassad funktion (t ex ett ajax-samtal). Hur kan du vara säker på att återuppringningsfunktionen kommer att ringas? Och om återuppringningen inte kallas kommer start () inte att ringas, och hela testningen av enheten kommer att hängas:
Så här är vad du gör:
// En anpassad funktionsfunktion ajax (successCallback) $ .ajax (url: 'server.php', framgång: successCallback); test ('asynkront test', funktion () // Pausa testet och misslyckas om start () inte kallas efter ett sekundstopp (1000); ajax (funktion () // ... asynkrona påståenden startar );))
Du skickar en timeout för att stoppa (), som berättar QUnit, "om start () inte kallas efter den timeouten, ska du misslyckas med detta test." Du kan vara säker på att hela testningen inte kommer att hänga och du får besked om något går fel.
Vad sägs om flera asynkrona funktioner? Var lägger du början ()? Du sätter den i setTimeout ():
// En anpassad funktionsfunktion ajax (successCallback) $ .ajax (url: 'server.php', framgång: successCallback); test ('asynkront test', funktion () // Pausa teststopp (); ajax (funktion () // ... asynkrona påståenden) ajax (funktion () // ... asynkrona påståenden) setTimeout () start ();, 2000);)
Timeouten ska vara tillräckligt lång så att både callbacks kan ringas innan testet fortsätter. Men vad händer om en av återkallelsen inte heter? Hur kan du veta det? Det här är var förväntat () kommer in:
// En anpassad funktionsfunktion ajax (successCallback) $ .ajax (url: 'server.php', framgång: successCallback); test ('asynkront test', funktion () // Pausa teststoppet (); // Berätta QUnit att du förväntar dig tre påståenden att springa förvänta (3); ajax (funktion () ok (sann);) ajax (funktion () ok (sant); ok (sant);) setTimeout (funktion () start ();, 2000);)
Du skickar in ett nummer för att förvänta dig () att berätta för QUnit att du förväntar dig att X många påståenden ska köras, om en av påståendet inte heter, kommer numret inte att matcha, och du får ett meddelande om att något gick fel.
Det finns också en genväg för förväntade (): du skickar bara numret som andra parameter för att testa () eller asyncTest ():
// En anpassad funktionsfunktion ajax (successCallback) $ .ajax (url: 'server.php', framgång: successCallback); // Berätta QUnit att du förväntar dig tre påståenden att köra testet ('asynkron test', 3, funktion () // Pausa teststoppet (); ajax (funktion () ok (sant);) ajax () ok (sant); ok (sant);) setTimeout (funktion () start ();, 2000);)
Det är allt du behöver veta för att komma igång med QUITIT. Enhetstester är en utmärkt metod för att testa din kod innan du publicerar den. Om du inte har skrivit några enhetstester innan är det dags att komma igång! Tack för att du läser!