Hoe u uw JavaScript-code kunt testen met QUnit

QUnit, ontwikkeld door het jQuery-team, is een uitstekend raamwerk voor het testen van uw JavaScript-eenheid. In deze tutorial zal ik introduceren wat QUnit specifiek is, en waarom je het belangrijk zou vinden om je code grondig te testen.

Wat is QUnit

QUnit is een krachtig framework voor het testen van JavaScript-eenheden dat u helpt bij het debuggen van code. Het is geschreven door leden van het jQuery-team en is de officiële testsuite voor jQuery. Maar QUnit is algemeen genoeg om een ​​normale JavaScript-code te testen, en het is zelfs in staat om JavaScript aan de serverzijde te testen via een JavaScript-engine zoals Rhino of V8.

Als u niet bekend bent met het "testen van eenheden", hoeft u zich geen zorgen te maken. Het is niet zo moeilijk om te begrijpen:

Bij computerprogrammering is unit testing een software verificatie- en valideringsmethode waarbij een programmeur test of individuele eenheden van broncode geschikt zijn voor gebruik. Een eenheid is het kleinste testbare deel van een toepassing. Bij procedureel programmeren kan een eenheid een individuele functie of procedure zijn.

Dit wordt geciteerd uit Wikipedia. Simpel gezegd, u schrijft tests voor elke functionaliteit van uw code en als al deze tests worden doorstaan, kunt u er zeker van zijn dat de code geen fouten bevat (meestal, afhankelijk van hoe grondig uw tests zijn).

Waarom u uw code moet testen

Als u nog geen unit-tests hebt geschreven, past u waarschijnlijk uw code gewoon rechtstreeks toe op een website, klikt u even om te kijken of er een probleem is en probeert u het te verhelpen zodra u er een ontdekt. Er zijn veel problemen met deze methode.

Ten eerste is het erg vervelend. Klikken is eigenlijk geen eenvoudige klus, want je moet ervoor zorgen dat alles wordt aangeklikt en het is zeer waarschijnlijk dat je één ding of twee mist. Ten tweede is alles wat u voor het testen hebt gedaan niet herbruikbaar, wat betekent dat het niet eenvoudig is om regressies te vinden. Wat is een regressie? Stel je voor dat je een code hebt geschreven en deze hebt getest, alle bugs hebt gerepareerd die je hebt gevonden en hebt gepubliceerd. Vervolgens stuurt een gebruiker feedback over nieuwe bugs en vraagt ​​hij enkele nieuwe functies aan. Je gaat terug naar de code, repareert deze nieuwe bugs en voegt deze nieuwe functies toe. Wat er vervolgens kan gebeuren, is dat sommige van de oude bugs opnieuw verschijnen, die 'regressies' worden genoemd. Kijk, nu moet je opnieuw klikken, en de kans is groot dat je deze oude bugs niet meer zult vinden; zelfs als je dat doet, duurt het een tijdje voordat je weet dat het probleem wordt veroorzaakt door regressies. Met unit testing, schrijf je tests om bugs te vinden, en als de code is aangepast, filter je deze opnieuw door de tests. Als er een regressie verschijnt, zullen sommige tests zeker mislukken en kunt u ze gemakkelijk herkennen, wetende welk deel van de code de bug bevat. Omdat je weet wat je zojuist hebt gewijzigd, kan het probleem eenvoudig worden opgelost.

Een ander voordeel van het testen van eenheden is met name voor webontwikkeling: het vereenvoudigt het testen van compatibiliteit tussen browsers. Voer uw tests gewoon uit in verschillende browsers en als een probleem zich voordoet in één browser, repareert u het en voert u deze tests opnieuw uit, waarbij u ervoor zorgt dat het geen regressie invoert in andere browsers. U kunt er zeker van zijn dat alle doelbrowsers worden ondersteund, zodra ze alle tests hebben doorstaan.

Ik zou graag een van de projecten van John Resig willen noemen: TestSwarm. Het vereist het testen van JavaScript-eenheden naar een nieuw niveau door het te verdelen. Het is een website die vele tests bevat, iedereen kan daar naartoe gaan, een aantal van de tests uitvoeren en het resultaat terugsturen naar de server. Op deze manier kan code heel snel worden getest op verschillende browsers en zelfs op verschillende platforms.

Unitstests schrijven met QUnit

Dus hoe schrijf je eenheidstests precies met QUnit? Eerst moet u een testomgeving instellen:

    QUnit Test Suite         

QUnit Test Suite

    Zoals u kunt zien, wordt hier een gehoste versie van het QUnit-framework gebruikt.

    De code die wordt getest, moet in myProject.js worden geplaatst en uw tests moeten in myTests.js worden ingevoegd. Om deze tests uit te voeren, opent u eenvoudig dit HTML-bestand in een browser. Nu is het tijd om een ​​aantal tests te schrijven.

    De bouwstenen van eenheidsbeproevingen zijn beweringen.

    Een bewering is een uitspraak die het terugkerende resultaat van uw code voorspelt. Als de voorspelling niet waar is, is de bewering mislukt en weet je dat er iets fout is gegaan.

    Als u beweringen wilt uitvoeren, moet u ze in een testcase plaatsen:

     // Laten we testen of deze functie function isEven (val) return val% 2 === 0;  test ('isEven ()', function () ok (isEven (0), 'Nul is een even getal'; ok (isEven (2), 'So is two'); ok (isEven (-4) , 'Dus is negatieve vier'); ok (! IsEven (1), 'Een is geen even getal'); ok (! IsEven (-7), 'No also is negative seven');)

    Hier hebben we een functie gedefinieerd, isEven, die detecteert of een getal even is, en we willen deze functie testen om ervoor te zorgen dat het geen onjuiste antwoorden retourneert.

    We noemen eerst test (), waarmee een testcase wordt gemaakt; de eerste parameter is een tekenreeks die in het resultaat wordt weergegeven en de tweede parameter is een callback-functie die onze beweringen bevat. Deze callback-functie wordt gebeld zodra QUnit wordt uitgevoerd.

    We hebben vijf beweringen geschreven, allemaal boolean. Een Booleaanse bewering verwacht dat de eerste parameter waar is. De tweede parameter is ook een bericht dat in het resultaat wordt weergegeven.

    Dit is wat u krijgt als u de test uitvoert:

    Aangezien al deze beweringen met succes zijn aangenomen, kunnen we daar vrij zeker van zijn ISEVEN () zal werken zoals verwacht.

    Laten we eens kijken wat er gebeurt als een bewering mislukt is.

     // Laten we testen of deze functie function isEven (val) return val% 2 === 0;  test ('isEven ()', function () ok (isEven (0), 'Nul is een even getal'; ok (isEven (2), 'So is two'); ok (isEven (-4) , 'Dus is negatieve vier'); ok (! IsEven (1), 'Een is geen even getal'; ok (! IsEven (-7), 'Negatieve zeven ook niet'); // Mislukt ok (isEven (3), 'Drie is een even getal');)

    Hier is het resultaat:

    De bewering is mislukt omdat we het opzettelijk verkeerd hebben geschreven, maar in je eigen project, als de test niet slaagt en alle beweringen kloppen, weet je dat er een bug is gevonden.

    Meer beweringen

    ok () is niet de enige bewering die QUnit biedt. Er zijn andere soorten beweringen die handig zijn bij het testen van uw project:

    Comparison Assertion

    De vergelijkingstoewijzing, equals (), verwacht dat de eerste parameter (die de werkelijke waarde is) gelijk is aan de tweede parameter (die de verwachte waarde is). Het lijkt op ok (), maar geeft zowel werkelijke als verwachte waarden af, waardoor het debuggen veel eenvoudiger wordt. Net als ok (), is er een optionele derde parameter nodig als een bericht dat moet worden weergegeven.

    Dus in plaats van:

     test ('assertions', function () ok (1 == 1, 'one equals one');)

    Je zou moeten schrijven:

     test ('assertions', function () is gelijk aan (1, 1, 'one equals one');)

    Let op de laatste "1", die de vergelijkingswaarde is.

    En als de waarden niet gelijk zijn:

     test ('assertions', function () is gelijk aan (2, 1, 'one equals one');)

    Het geeft veel meer informatie, waardoor het leven een stuk eenvoudiger wordt.

    De vergelijkingstoewijzing gebruikt "==" om de parameters te vergelijken, dus het is niet geschikt voor array- of objectvergelijking:

     test ('test', function () is gelijk aan (, , 'mislukt, dit zijn verschillende objecten'); equals (a: 1, a: 1, 'failed'); equals ([ ], [], 'mislukt, er zijn verschillende arrays'); equals ([1], [1], 'failed');)

    Om dit soort gelijkheid te testen, biedt QUNIT een andere soort bewering: identieke bewering.

    Identieke bewering

    Identieke bewering, same (), verwacht dezelfde parameters als equals (), maar het is een diepe recursieve vergelijkingsbevestiging die niet alleen op primitieve typen werkt, maar ook op arrays en objecten. Assertions, in het vorige voorbeeld, zullen allemaal slagen als je ze verandert in identieke beweringen:

     test ('test', function () same (, , 'passes, objecten hebben dezelfde inhoud'); same (a: 1, a: 1, 'passes'); same ( [], [], 'passen, arrays hebben dezelfde inhoud'); zelfde ([1], [1], 'passen');)

    Merk op dat dezelfde () '===' gebruikt om een ​​vergelijking te maken wanneer dat mogelijk is, dus het komt van pas bij het vergelijken van speciale waarden:

     test ('test', function () equals (0, false, 'true'); same (0, false, 'false'); equals (null, undefined, 'true'); same (null, undefined, ' false ');)

    Structuur uw beweringen

    Alle beweringen in één testcase plaatsen is een heel slecht idee, omdat het erg moeilijk te onderhouden is en geen schoon resultaat oplevert. Wat je moet doen, is ze te structureren, ze in verschillende testcases te plaatsen, elk gericht op een enkele functionaliteit.

    U kunt testcases zelfs indelen in verschillende modules door de modulefunctie aan te roepen:

     module ('Module A'); test ('een test', functie () ); test ('een andere test', functie () ); module ('Module B'); test ('een test', functie () ); test ('een andere test', functie () );

    Asynchrone test

    In voorgaande voorbeelden worden alle beweringen synchroon genoemd, wat betekent dat ze één na één worden uitgevoerd. In de echte wereld zijn er ook veel asynchrone functies, zoals ajax-aanroepen of functies die door setTimeout () en setInterval () worden opgeroepen. Hoe kunnen we dit soort functies testen? QUnit biedt een speciaal soort testcase met de naam "asynchrone test", die is bedoeld voor asynchrone tests:

    Laten we eerst proberen het op een normale manier te schrijven:

     test ('asynchrone test', functie () setTimeout (function () ok (true);, 100))

    Zien? Het is alsof we geen enkele bewering hebben geschreven. Dit komt omdat de bewering asynchroon liep, tegen de tijd dat deze werd genoemd, was de testcase al voltooid.

    Hier is de juiste versie:

     test ('asynchrone test', functie () // Pauzeer de eerste teststop (); setTimeout (function () ok (true); // Nadat de bevestiging is aangeroepen, // ga door met de teststart (); , 100))

    Hier gebruiken we stop () om de testcase te onderbreken en nadat de bewering is aangeroepen, gebruiken we start () om door te gaan.

    Het aanroepen van stop () onmiddellijk na het aanroepen van test () is heel gebruikelijk; dus biedt QUnit een snelkoppeling: asyncTest (). U kunt het vorige voorbeeld als volgt herschrijven:

     asyncTest ('asynchrone test', functie () // De test wordt automatisch gepauzeerd setTimeout (function () ok (true); // Nadat de bevestiging is aangeroepen, // ga door met de teststart ();, 100 ))

    Er is één ding om op te letten: setTimeout () zal altijd zijn callback-functie aanroepen, maar wat als het een aangepaste functie is (bijvoorbeeld een ajax-oproep). Hoe weet je zeker dat de callback-functie wordt aangeroepen? En als de callback niet wordt aangeroepen, wordt start () niet aangeroepen en hangt het testen van de hele eenheid af:

    Dus dit is wat je doet:

     // Een aangepaste functie functie ajax (successCallback) $ .ajax (url: 'server.php', success: successCallback);  test ('asynchrone test', functie () // Pauzeer de test en slaag deze als start () niet wordt aangeroepen na één seconde stop (1000); ajax (function () // ... asynchrone assertions start ( );))

    U geeft een time-out door aan stop (), waarmee QUnit wordt verteld: "als start () na die time-out niet wordt aangeroepen, moet u deze test weigeren." U kunt er zeker van zijn dat de hele test niet zal vastlopen en u wordt op de hoogte gebracht als er iets misgaat.

    Hoe zit het met meerdere asynchrone functies? Waar zet je de start ()? Je zet het in setTimeout ():

     // Een aangepaste functie functie ajax (successCallback) $ .ajax (url: 'server.php', success: successCallback);  test ('asynchrone test', functie () // Pauzeer de teststop (); ajax (function () // ... asynchronous assertions) ajax (function () // ... asynchronous assertions) setTimeout (function () start ();, 2000);)

    De time-out moet redelijk lang genoeg zijn om beide callbacks te kunnen gebruiken voordat de test wordt voortgezet. Maar wat als een van de callback niet wordt gebeld? Hoe kun je dat weten? Dit is waar expect () komt in:

     // Een aangepaste functie functie ajax (successCallback) $ .ajax (url: 'server.php', success: successCallback);  test ('asynchrone test', functie () // Pauzeer de teststop (); // Vertel QUnit dat u verwacht dat drie beweringen worden uitgevoerd (3); ajax (function () ok (true);) ajax (function () ok (true); ok (true);) setTimeout (function () start ();, 2000);)

    U geeft een getal door om te verwachten () dat u aan QUnit vertelt dat u verwacht dat X veel assertions uitvoert, als een van de beweringen niet wordt aangeroepen, komt het nummer niet overeen en ontvangt u een melding dat er iets fout is gegaan.

    Er is ook een snelkoppeling voor expect (): u geeft het nummer net door als de tweede parameter om te testen () of asyncTest ():

     // Een aangepaste functie functie ajax (successCallback) $ .ajax (url: 'server.php', success: successCallback);  // Vertel QUnit dat u drie asserts verwacht om de test uit te voeren ('asynchrone test', 3, function () // Pauzeer de teststop (); ajax (function () ok (true);) ajax (function () ok (true); ok (true);) setTimeout (function () start ();, 2000);)

    Conclusie

    Dat is alles wat u moet weten om te beginnen met QUnit. Het testen van eenheden is een geweldige methode om uw code te testen voordat u deze publiceert. Als je nog geen unit tests hebt geschreven, is het tijd om te beginnen! Bedankt voor het lezen!

    • Volg ons op Twitter of abonneer je op de Nettuts + RSS Feed voor de beste tutorials voor webontwikkeling op internet.