Unit-Tests strukturieren

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Sie möchten Ihre Tests strukturieren, um das Testen zu vereinfachen.

Lösung

Beachten Sie, wie im Rezept Eingebettete Unit-Tests zu Hilfs-Stylesheets hinzufügen die Testdaten in den Test-Stylesheets eingebettet sind. Jedes test-Element enthält ein num-Attribut sowie das erwartete Ergebnis in Form eines ans-Attributs. Die Testumgebung extrahiert dann diese test-Elemente aus dem Stylesheet, führt die Tests aus und vergleicht jeweils das erwartete mit dem tatsächlichen Ergebnis. Die wichtigste Eigenschaft der Testumgebung ist die, dass sie keine Ausgabe erzeugt, wenn der Test erfolgreich verläuft.

Diskussion

Einen der besten Ratschläge zum Thema automatisiertes Testen finden Sie in dem Buch The Practice of Programming von Brian W. Kernighan und Rob Pike (Addison-Wesley, 1999). Darin fordern die Autoren, dass Testprogramme nur dann eine Ausgabe erzeugen sollten, wenn Tests fehlschlagen. Warum wohl? Wollen Sie sich durch Unmengen von Seiten an Testausgaben durchkämpfen, um jene Fälle zu suchen, wo ein Test fehlschlägt? Wenn Sie hingegen davon ausgehen, dass der Testcode keine Ausgabe erzeugt, dann werden Sie Fehler schnell finden, sobald es doch eine Ausgabe gibt. Bevor Sie sich auf dieses Verfahren verlassen, sollten Sie natürlich auch Ihren Testcode testen, um sicherzugehen, dass er wirklich ausgeführt wird.

Die Methode, bei der das Ergebnis als Attribut im test-Element gespeichert wird, funktioniert hinreichend gut für einfache Tests, die ein primitives Ergebnis produzieren. Manche Templates jedoch produzieren eine Knotenmenge. In diesem Fall müssen Sie eventuell das erwartete Ergebnis als Kindelemente in den Tests speichern. Dann können Sie die Ergebnisse mit den Mengenoperationen aus dem Rezept Mengenoperationen auf Knotenmengen mit Hilfe von Wertsemantiken ausführen vergleichen. Manchmal können Sie Templates, die eine Knotenmenge produzieren, aber auch auf einfachere Weise testen. Betrachten Sie die Testumgebung für das Template math:lowest. Wie Sie sich erinnern, gibt math:lowest die Menge der Knoten zurück, die aus allen Instanzen der kleinsten Zahl in einer Eingabeknotenmenge besteht:

<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="http://www.exslt.org/math" exclude-result-prefixes="math test" xmlns:test="http://www.ora.com/XSLTCookbook/test" id="math:math.lowest">
  <xsl:import href="math.min.xslt"/>
  <xsl:template name="math:lowest">
    <xsl:param name="nodes" select="/.."/>
    <xsl:variable name="min">
      <xsl:call-template name="math:min">
        <xsl:with-param name="nodes" select="$nodes"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="number($min) = $min">
        <xsl:copy-of select="$nodes[. = $min]"/>
      </xsl:when>
      <xsl:otherwise/>
    </xsl:choose>
  </xsl:template>
  <!-- TEST-CODE: NICHT ENTERNEN! -->
  <xsl:template match="xsl:stylesheet[@id='math:math.lowest'] | xsl:include[@href='math.lowest.xslt'] " xmlns:exsl="http://exslt.org/common">
    <xsl:message>TESTING math.lowest</xsl:message>
    <xsl:choose>
      <xsl:when test="function-available('exsl:node-set')">
        <xsl:for-each select="document('')/*/test:test">
          <xsl:variable name="ans">
            <xsl:call-template name="math:lowest">
              <xsl:with-param name="nodes" select="test:data"/>
            </xsl:call-template>
          </xsl:variable>
          <xsl:variable name="$ans-ns" select=" exsl:node-set($ans)"/>
          <xsl:if test="not($ans-ns/* != test:data[. = current( )/@ans]) and count($ans-ns/*) != count(test:data[. = current( )/@ans])">
            <xsl:message>math:lowest TEST von <xsl:value-of select="@num"/> FEHLGESCHLAGEN [<xsl:copy-of select="$ans-ns"/>] [<xsl:copy-of select="test:data[. = current( )/@ans]"/>]</xsl:message>
          </xsl:if>
        </xsl:for-each>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message>WARNUNG: Testcode von math.lowest benötigt exsl:node-set THIS VERSION=[<xsl:value-of select="system-property('xsl:version')"/>] VENDOR=[<xsl:value-of select="system-property('xsl:vendor')"/>]</xsl:message>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <test:test num="1" ans="1" xmlns="http://www.ora.com/XSLTCookbook/test">
    <data>9</data>
    <data>8</data>
    <data>7</data>
    <data>6</data>
    <data>5</data>
    <data>4</data>
    <data>3</data>
    <data>2</data>
    <data>1</data>
  </test:test>
  <!-- weitere Tests hier ... >
</xsl:stylesheet>

Der Vergleich basiert auf dem Verhalten von != für den Fall, dass beide Seiten aus Knotenmengen bestehen: Das Ergbnis ist true, falls für ein Knotenpaar mit je einem Knoten aus beiden Mengen die Knoten verschiedene String-Werte haben. Sie können sicherstellen, dass die zurückgegebenen Knoten, die sich aus der Wahl der Ergebnisknoten aus der Testmenge ergeben, identisch sind mit denen, die von math:lowest zurückgegeben werden. Außerdem können Sie sicherstellen, dass die Anzahl beider identisch ist.

Manche Berechnungsmethoden (insbesondere mathematische Näherungsverfahren) führen zu Ergebnissen, die selbst dann korrekt sind, wenn der erzeugte Wert nicht exakt mit dem theoretisch korrekten Ergebnis übereinstimmt. In diesem Fall können Sie eine Fehlertoleranz im Testcode angeben und sicherstellen, dass das berechnete Ergebnis innerhalb dieser Toleranz mit dem korrekten Ergebnis übereinstimmt.

Siehe auch

Das Buch von Brian W. Kernighan und Rob Pike, The Practice of Programming (Addison-Wesley, 1999), wurde zwar nicht speziell für XSLT geschrieben, enthält aber sehr gute Ratschläge für das Testen und Debuggen aller möglichen Arten von Programmen.

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2006 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT Kochbuch" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O'Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de