Quantcast
Viewing all articles
Browse latest Browse all 7

Få orden i JavaScript-testene med QUnit

Når man skriver i et dynamisk språk som JavaScript med mye kraft i fingerspissene er det lett å ødelegge det man allerede har fått på plass. Hvor mange ganger har du ikke skutt deg selv i foten på grunn av underlige syntaksregler eller dårlig dokumentasjon? En solid samling enhetstester kan forhindre dette og gjøre deg trygg på at koden din fungerer.

"QUnit er et lettvektig rammeverk
for enhetstesting i JavaScript"

QUnit er et lettvektig rammeverk for enhetstesting i JavaScript. Denne artikkelen forklarer hva QUnit gjør og hvordan man bruker det. Med QUnit kan du blant annet:

  • Enhetsteste din eksisterende kode
  • Få testresultatene opp formatert på en side
  • Teste asynkron kode, som f.eks. animasjoner eller ajax
  • Teste server-side kode
  • Fasilitere automatisert testkjøring og resultatrapportering

QUnit bygger på jQuery — det populære Javascript-biblioteket — og blir brukt som det interne testverktøyet på jQuery-teamet. Slik ser testresultater ut i QUnit:

Image may be NSFW.
Clik here to view.

QUnit basics

En demonstrasjon sier mer enn tusen ord. Slik skriver man en enkel test i QUnit:

test('Beskriv testen her', function() {
   var x = Math.max(3, 4);
   equals(x, 4);
   var y = Math.max(3, 4);
   notEquals(x, y, "Beskriv evt. assertion her");
});

Her er equals() og notEquals() assertions som får testen til å feile om de ikke stemmer. Dette ligner kjente testerammeverk som f.eks. JUnit. Tilgjengelige assertions i QUnit er:

ok(a)
Sjekker om a er true.

equal(a,b), notEqual(a,b)
Sammenligner a og b, og viser den spesifikke forskjellen om de ikke matcher. For eksempel:

Image may be NSFW.
Clik here to view.

strictEqual(a,b), notStrictEqual(a,b)
Samme som equals, men sjekker om også typen til a matcher b. (F.eks. strictEquals(2, “2″) feiler.)

deepEqual(a,b), notDeepEqual(a,b)
Sjekker rekursivt feltene inni a og b for å se om hver av dem matcher.

raises(f), raises(f,e)
Sjekker om et exception kastes når funksjonen f kjøres. Evt. kan typen exception spesifiseres i e.

Strukturer testene med moduler

Antall tester kan bli mange, men QUnit har mekanismer for å strukturere tester i grupper og la dem dele felles kode for å sette opp og rydde opp etter testene. Sett inn module() for å separere tester som hører sammen:

module('Touch-komponenten');

test(...);
test(...);

module('Søketjenesten');

test(...);
test(...);

Disse modulene kan også ta imot setup- og teardown-funksjoner som kjøres før og etter hver test:

module("Ajaxtestene", {
 setup: function() {
    // kjøres før test
 },
 teardown: function() {
    // kjøres etter test
 }
});

Test asynkron JavaScript

Mye av moroa med JavaScript er asynkrone metoder. Det vil si at etter at man gjør kall på en asynkron metode fortsetter koden etter kallet å kjøre, mens den asynkrone metoden også kjøres samtidig. Typisk brukes slike asynkrone metoder i ajax-kall og animasjoner, og de får som regel en callback-metode som kjøres når de er ferdig. For eksempel er jQuerys ajax-metode asynkron:

function asynkronMetode(callback) {
    $.ajax({
       url: 'server.php',
       success: callback
    });
}

Hvordan kan man teste asynkrone metoder? Dette er vanskeligere enn man kanskje tror. Om man kjører assertions etter et asynkront kall kan det hende at den asynkrone koden ikke er ferdig enda, og assertionene vil feile. Hva om man heller putter assertions inni callbacken slik at de kjøres når den asynkrone koden er ferdig? Nei, det går ikke fordi hele testen kan samtidig kjøre seg ferdig og dermed vellykket før assertionene får kommet på banen, og da merker man ikke om de feiler.

"Mye av moroa med JavaScript
er asynkrone metoder"

QUnit tilbyr en metode stop() som pauser testen slik at man kan vente på asynkrone kall. Testen startes igjen ved å kalle start(). JavaScript tilbyr allerede en metode setTimeout() som kan sørge for å vente så og så lenge før start() kjøres. Høres ut som vi har det vi trenger for å teste asynkron kode!

Men hva om et asynkront kall henger lenger enn tiden setTimeout venter? Da vil den asynkrone metodens assertions aldri kjøre, og ingen assertions betyr tilsynelatende vellykket test, uavhengig av om det funket eller ikke! Løsningen er å spesifisere antall assertions man forventer å gjøre med expect(). Slik vil testen feile om noe asynkron kode aldri returnerte.

Her er et eksempel som omfatter disse asynkrone mekanismene:

test('Min asynkrone test', function() {
    expect(3); // Vi forventer 3 assertions
    stop();  // Pause testen

    asynkronMetode(function() {
       equals(bla, bla);
    })  

    asynkronMetode(function() {
      equals(bla, bla);
      equals(bla, bla);
    })  

    setTimeout(function() {
       start();  // Fortsett testen etter 2 sekunder
    }, 2000);
});

Automatiser testene og presenter resultatene

Enhetstesting i QUnit ser vel og bra ut, men hvordan får man testene kjørt og testresultatene presentert på en fin måte? Heldigvis følger det med funksjoner og CSS i QUnit for dette. Følgende html-kode kjører testene i mine_tester.js og presenter resultatene slik som sett i skjermdumpen øverst i denne artikkelen:

<html>
<head>
    <script src="http://pre.jquery.com/jquery-latest.js"></script>
    <link rel="stylesheet" href="http://pre.jquery.com/qunit/git/qunit.css" type="text/css" />
    <script type="text/javascript" src="http://pre.jquery.com/qunit/git/qunit.js"></script>

    <script type="text/javascript" src="mine_tester.js"></script>
</head>
<body>
    <h1 id="qunit-header">Min overskrift her</h1>
    <h2 id="qunit-banner"></h2>
    <div id="qunit-testrunner-toolbar"></div>
    <h2 id="qunit-userAgent"></h2>
    <ol id="qunit-tests"></ol>
    <div id="qunit-fixture">test markup, will be hidden</div>
</body>
</html>

"QUnit vil skape strukturert html
med testresultatene"

Som man ser krever QUnit jQuery-biblioteket, og kommer til å fylle html-elementene i

med riktig innhold ut fra hvilken id de har. Den medfølgende CSS-en kan såklart byttes ut med ens egne stilark. Og QUnit vil skape strukturert html med testresultatene som så kan analyseres av automatiske verktøy. Slik vil for eksempel oppsummeringen av resultene se ut:
<p id="qunit-testresult" class="result">
    Tests completed in 76 milliseconds.<br>
    <span class="passed">5</span> tests of
    <span class="total">8</span> passed,
    <span class="failed">3</span> failed.
</p>

QUnit API-et tilbyr også en rekke callbacks som kalles i de ulike stadiene av testingen. F.eks. QUnit.begin(), QUnit.testDone() og QUnit.moduleDone(), hvis funksjonalitet bør være selvforklarende. Alt dette fasiliterer automatiske tredjeparts testverktøy.

Konklusjon

QUnit er et enkelt rammeverk for enhetstesting i JavaScript. Det har støtte for assertions slik man kjenner fra andre rammeverk som JUnit, og man kan strukturere testene i modules. Mekanismer for testing av asynkron kode finnes også, samt støtte for tredjeparts automatiserte verktøy for å kjøre testene og presentere resultatene. API-en er liten, men gir deg de verktøyene man trenger for å innføre enhetstester i din eksisterende kode, og det er veldig lett å sette i gang. Les mer om QUnit på nettsidene deres, og sjekk ut denne artikkelen om asynkron testing i QUnit.


Viewing all articles
Browse latest Browse all 7

Trending Articles