XQuery testen: Bücher auswählen und sortieren

Ein Katalog enthält veröffentlichte Bücher und Entwürfe. Für einen Export sollen nur die veröffentlichten Bücher ausgegeben werden, nach Titel sortiert. Das ist eine typische kleine XQuery-Aufgabe und ein guter Kandidat für einen Test.

Die Funktion bekommt den Katalog als Parameter. Eine XML-Datenbank oder ein externer Dienst ist dafür nicht nötig. So können wir zuerst die Auswahl und Sortierung prüfen, ohne uns um Zugangsdaten oder wechselnde Serverinhalte zu kümmern.

Das Modul und die Eingabedaten

Das XQuery-Modul sieht so aus:

examples/05-xquery/catalog.xqm

xquery version "3.1";
module namespace cat = "urn:example:catalog";

declare function cat:published(
  $catalog as element(catalog)
) as element(book)* {
  for $book in $catalog/book[@status = "published"]
  order by string($book/title) collation
    "http://www.w3.org/2005/xpath-functions/collation/codepoint"
  return $book
};

Die Funktion erwartet ein catalog-Element und liefert eine Sequenz von book-Elementen. Die Codepoint-Kollation legt die Sortierung ausdrücklich fest. Dadurch hängt die Reihenfolge nicht von einer zufälligen Spracheinstellung der Umgebung ab.

Die Testdaten enthalten absichtlich einen Entwurf. Außerdem stehen die veröffentlichten Bücher noch nicht in der gewünschten Reihenfolge:

examples/05-xquery/catalog.xml

<catalog>
  <book id="b2" status="published"><title>XML Workflows</title></book>
  <book id="b3" status="draft"><title>Unfinished Book</title></book>
  <book id="b1" status="published"><title>Publishing Systems</title></book>
</catalog>

Aufruf und erwartete Bücher beschreiben

In der XSpec-Datei benennt query den Modulnamensraum und query-at den Speicherort. Die Angaben haben also unterschiedliche Aufgaben: query ist nicht der Dateipfad.

examples/05-xquery/catalog.xspec

<?xml version="1.0" encoding="UTF-8"?>
<x:description xmlns:x="http://www.jenitennison.com/xslt/xspec"
  xmlns:cat="urn:example:catalog" query="urn:example:catalog"
  query-at="catalog.xqm">
  <x:scenario label="Select and sort published books">
    <x:call function="cat:published">
      <x:param href="catalog.xml" select="/catalog"/>
    </x:call>
    <x:expect label="Return only published books in title order"
      href="published.xml" select="/catalog/book"/>
  </x:scenario>
  <x:scenario label="Handle an empty catalog">
    <x:call function="cat:published">
      <x:param select="catalog"><catalog/></x:param>
    </x:call>
    <x:expect label="Return an empty sequence" select="()"/>
  </x:scenario>
</x:description>

Die Datei mit dem erwarteten Ergebnis enthält nur die beiden veröffentlichten Bücher, bereits richtig sortiert:

examples/05-xquery/published.xml

<catalog>
  <book id="b1" status="published"><title>Publishing Systems</title></book>
  <book id="b2" status="published"><title>XML Workflows</title></book>
</catalog>

Der Test wählt daraus die book-Elemente aus, denn genau diese Sequenz liefert die Funktion. Ein zweites Szenario prüft den leeren Katalog. Erwartet wird die leere Sequenz (), nicht ein leeres catalog-Element und auch kein leerer String. Dieser Unterschied ist zum Beispiel wichtig, wenn anschließend die Treffer gezählt werden.

Die Tests starten

Mit dem Paket-Runner lautet der Aufruf:

python scripts/run-tests.py --only xquery

Direkt mit XSpec wird der XQuery-Modus durch -q gewählt. Die Standardumgebung dieses Pakets verwendet dafür Saxon.

"$XSPEC_HOME/bin/xspec.sh" -q -e -j examples/05-xquery/catalog.xspec

Damit werden Auswahl und Sortierung geprüft. Ob auf einem Datenbankserver die richtigen Indizes genutzt werden, Berechtigungen stimmen oder Transaktionen funktionieren, ist damit noch nicht getestet.

Für solche Aufgaben kommt ein eigener Integrationstest mit dem tatsächlichen Zielprozessor und kontrollierten Daten hinzu. Datenbankspezifische Funktionen sollten nicht einfach als mit Saxon austauschbar behandelt werden.

Das gleiche Muster passt zu vielen Publishing-Aufgaben: Metadaten filtern, Inhaltsverzeichnisse zusammenstellen, Registereinträge sortieren oder eine Exportauswahl erzeugen. In den Testdaten sollte neben den gewünschten Treffern immer auch etwas stehen, das nicht in die Ausgabe gehört.

<< zurück                                                                                                             vor >>