Vollzeitblogger

Node.js tests mit Mocha

November 16, 2013

TDD oder Test Driven Development ist eine der Praktiken die an Beliebtheit gewinnen. In diesem kurzen Tutorial möchte ich kurz zeigen wie man diese Umgebung mit Node.js und Mocha umsetzt. Ein wichtiger Ansatz ist zuerst die Tests zu schreiben, also zu wissen was ein Teil des Programmes bewältigen soll und danach die eigentliche Logik zu verfassen, die einen dorthin bringt.

Mocha, das JavaScript Test Framework

Mocha ist das JavaScript Test Framework für das wir unsere Tests schreiben werden.

Es wurde hauptsächlich von TJ Holowaychuk entwickelt und ist über npm verfügbar. Um es global zu installieren braucht es nur:

<code>npm install -g mocha
</code>

TDD, der erste Test

In einem neuen Verzeichnis erstellen wir zunächst einen Order für Tests, den wir test nennen. Im test Verzeichnis erstellen wir auch noch eine Datei, die wir test.js nennen.

Als nächstes installieren wir noch mocha und expect.js als lokale Abhängigkeiten über npm:

<code>npm install mocha
npm install expect.js
</code>

Damit wir auch ein zu testendes Modul vorfinden, erstellen wir noch die Datei hello.js.

Um zu prüfen ob eine Hallo Welt Funktion auch ihren Dienst tut und erfolgreich mit Variablen gefüttert werden kann um zum Beispiel auch Hallo Inge auszugeben, erstellen wir Tests in der Datei test.js.

<code>describe('hello',function() {
    it('sollte eine Funktion sein', function() {
        expect(hello).to.be.a('function');
    });

    it('Sollte einen String zurück geben', function() {
        expect(hello('foo')).to.be.a('string');
    });

    it('Sollte "Hallo " + $input + "!" ausgeben', function() {
        expect(hello('Dörthe')).to.equal('Hallo Dörthe!');
    });
});
</code>

Um die Tests laufen zu lassen führen wir einfach im Verzeichnis, das sowohl hello.js als auch das Verzeichnis test enhält mocha aus. Dies sollte dann etwa so aussehen, da wir bisher keinen Inhalt in hello.js haben.

<code>[mocha-tutorial]$ mocha

  ․․․

  0 passing (8ms)
  3 failing

  1) hello sollte eine Funktion sein:
        [...]

  2) hello Sollte einen String zurück geben:
        [...]

    3) hello Sollte "Hallo " + $input + "!" ausgeben:
        [...]
</code>

Wenn wir nun die entsprechende Funktion schreiben, die mit einem Namen als Eingabe, einen Gruß zurück gibt, wie in meiner hello.js Datei, werden alle Tests bestanden:

<code>module.exports = function(name) {
    return 'Hallo ' + name + '!';
}
</code>

Wenn wir mocha erneut testen lassen bekommen wir keine weiteren Infos, als dass alle Tests erfolgreich waren:

<code>[mocha-tutorial]$ mocha

  ․․․

  3 passing (9ms)
</code>

Fazit

Test Driven Development mit node.js ist relativ simpel und Mocha tut seinen Teil um das mit wenigen Zeilen und sehr verständlichen Beispielen zu illustrieren.

Ich schreibe selten Tests zuerst, aber wenn Projekte wachsen und Bugs auftauchen, weil der Entwickler vor dem commit und push etwas kaputt gemacht hat, ist es einfach praktischer wenn man zumindest für kritische Teile des Projektes Tests hat, die solche Szenarien verhindern.

Anhang

Hier noch einmal der ganze Output, den ich oben gekürzt habe:

<code>[mocha-tutorial]$ mocha

  ․․․

  0 passing (8ms)
  3 failing

  1) hello sollte eine Funktion sein:
     Error: expected {} to be a function
      at Assertion.assert (/home/geronimo/projects/jsn-code/mocha-tutorial/node_modules/expect.js/expect.js:99:13)
      at Assertion.a.Assertion.an [as a] (/home/geronimo/projects/jsn-code/mocha-tutorial/node_modules/expect.js/expect.js:251:12)
      at Function.a (/home/geronimo/projects/jsn-code/mocha-tutorial/node_modules/expect.js/expect.js:480:17)
      at Context.<anonymous> (/home/geronimo/projects/jsn-code/mocha-tutorial/test/test.js:7:23)
      at Test.Runnable.run (/usr/lib/node_modules/mocha/lib/runnable.js:211:32)
      at Runner.runTest (/usr/lib/node_modules/mocha/lib/runner.js:358:10)
      at /usr/lib/node_modules/mocha/lib/runner.js:404:12
      at next (/usr/lib/node_modules/mocha/lib/runner.js:284:14)
      at /usr/lib/node_modules/mocha/lib/runner.js:293:7
      at next (/usr/lib/node_modules/mocha/lib/runner.js:237:23)
      at Object._onImmediate (/usr/lib/node_modules/mocha/lib/runner.js:261:5)
      at processImmediate [as _immediateCallback] (timers.js:330:15)

  2) hello Sollte einen String zurück geben:
     TypeError: object is not a function
      at Context.<anonymous> (/home/geronimo/projects/jsn-code/mocha-tutorial/test/test.js:11:10)
      at Test.Runnable.run (/usr/lib/node_modules/mocha/lib/runnable.js:211:32)
      at Runner.runTest (/usr/lib/node_modules/mocha/lib/runner.js:358:10)
      at /usr/lib/node_modules/mocha/lib/runner.js:404:12
      at next (/usr/lib/node_modules/mocha/lib/runner.js:284:14)
      at /usr/lib/node_modules/mocha/lib/runner.js:293:7
      at next (/usr/lib/node_modules/mocha/lib/runner.js:237:23)
      at Object._onImmediate (/usr/lib/node_modules/mocha/lib/runner.js:261:5)
      at processImmediate [as _immediateCallback] (timers.js:330:15)

  3) hello Sollte "Hallo " + $input + "!" ausgeben:
     TypeError: object is not a function
      at Context.<anonymous> (/home/geronimo/projects/jsn-code/mocha-tutorial/test/test.js:15:10)
      at Test.Runnable.run (/usr/lib/node_modules/mocha/lib/runnable.js:211:32)
      at Runner.runTest (/usr/lib/node_modules/mocha/lib/runner.js:358:10)
      at /usr/lib/node_modules/mocha/lib/runner.js:404:12
      at next (/usr/lib/node_modules/mocha/lib/runner.js:284:14)
      at /usr/lib/node_modules/mocha/lib/runner.js:293:7
      at next (/usr/lib/node_modules/mocha/lib/runner.js:237:23)
      at Object._onImmediate (/usr/lib/node_modules/mocha/lib/runner.js:261:5)
      at processImmediate [as _immediateCallback] (timers.js:330:15)
</code>

© 2023, by Jonathan M. Hethey