Testen mit nf-test¶
KI-gestützte Übersetzung - mehr erfahren & Verbesserungen vorschlagen
Die Fähigkeit, systematisch zu überprüfen, ob jeder Teil deines Workflows das tut, was er soll, ist entscheidend für die Reproduzierbarkeit und langfristige Wartbarkeit – und kann während der Entwicklung eine enorme Hilfe sein.
Lass uns kurz darüber sprechen, warum Testen so wichtig ist. Wenn du einen Workflow entwickelst, wirst du als Erstes einige Testdaten nehmen, von denen du weißt, dass sie gültig sind und ein Ergebnis liefern sollten. Du fügst den ersten Prozess zur Pipeline hinzu und verbindest ihn mit deinen Eingaben, damit er funktioniert. Dann führst du ihn mit den Testdaten aus, um zu prüfen, ob alles funktioniert. Wenn das klappt, gehst du zum nächsten Prozess über und führst die Testdaten erneut aus. Du wiederholst diesen Vorgang, bis du eine Pipeline hast, mit der du zufrieden bist.
Dann fügst du vielleicht einen einfachen true/false-Parameter wie --skip_process hinzu. Jetzt musst du die Pipeline zweimal ausführen – einmal mit jedem Parameter –, um sicherzustellen, dass sie wie erwartet funktioniert. Aber warte mal: Wie überprüfen wir, ob --skip_process den Prozess tatsächlich überspringt? Wir müssen die Ausgaben durchsuchen oder die Log-Dateien prüfen! Das ist mühsam und fehleranfällig.
Während du deine Pipeline weiterentwickelst, wird sie schnell so komplex, dass das manuelle Testen jeder Iteration langsam und fehleranfällig wird. Außerdem wird es sehr schwierig sein, genau zu bestimmen, wo in deiner Pipeline ein Fehler herkommt, wenn du einen findest. Hier kommt das Testen ins Spiel.
Testen ermöglicht es dir, systematisch zu überprüfen, ob jeder Teil deiner Pipeline wie erwartet funktioniert. Die Vorteile gut geschriebener Tests für Entwickler*innen sind enorm:
- Vertrauen: Da die Tests die gesamte Pipeline abdecken, kannst du sicher sein, dass eine Änderung nichts anderes beeinflusst.
- Zuverlässigkeit: Wenn mehrere Entwickler*innen an der Pipeline arbeiten, wissen sie, dass die anderen die Pipeline und alle Komponenten nicht kaputt gemacht haben.
- Transparenz: Die Tests zeigen, wo eine Pipeline fehlschlägt, und erleichtern die Fehlersuche. Sie dienen auch als eine Form der Dokumentation und zeigen, wie ein Prozess oder Workflow ausgeführt wird.
- Geschwindigkeit: Da die Tests automatisiert sind, können sie sehr schnell und wiederholt ausgeführt werden. Du kannst schnell iterieren und musst weniger befürchten, neue Fehler einzuführen.
Es gibt viele verschiedene Arten von Tests, die wir schreiben können:
- Tests auf Modulebene: Für einzelne Prozesse
- Tests auf Workflow-Ebene: Für einen einzelnen Workflow
- Tests auf Pipeline-Ebene: Für die Pipeline als Ganzes
- Performance-Tests: Für die Geschwindigkeit und Effizienz der Pipeline
- Stresstests: Bewertung der Leistung der Pipeline unter extremen Bedingungen, um ihre Grenzen zu bestimmen
Das Testen einzelner Prozesse ist analog zu Unit-Tests in anderen Sprachen. Das Testen des Workflows oder der gesamten Pipeline ist analog zu sogenannten Integrationstests in anderen Sprachen, bei denen wir die Interaktionen der Komponenten testen.
nf-test ist ein Tool, mit dem du Tests auf Modul-, Workflow- und Pipeline-Ebene schreiben kannst. Kurz gesagt: Es ermöglicht dir, systematisch zu überprüfen, ob jeder einzelne Teil der Pipeline wie erwartet funktioniert – isoliert.
Lernziele¶
In dieser Side Quest lernst du, nf-test zu verwenden, um einen Test auf Workflow-Ebene für die Pipeline sowie Tests auf Modulebene für die drei aufgerufenen Prozesse zu schreiben.
Am Ende dieser Side Quest wirst du folgende Techniken effektiv einsetzen können:
- nf-test in deinem Projekt initialisieren
- Tests auf Modul- und Workflow-Ebene generieren
- Gängige Arten von Assertions hinzufügen
- Verstehen, wann Snapshots vs. direkte Inhalts-Assertions verwendet werden sollten
- Tests für ein gesamtes Projekt ausführen
Diese Fähigkeiten helfen dir, eine umfassende Teststrategie in deinen Pipeline-Projekten umzusetzen und sie robuster und wartbarer zu machen.
Voraussetzungen¶
Bevor du diese Side Quest in Angriff nimmst, solltest du:
- Das Tutorial Hello Nextflow oder einen gleichwertigen Einsteigerkurs abgeschlossen haben.
- Mit grundlegenden Nextflow-Konzepten und -Mechanismen vertraut sein (Prozesse, Kanäle, Operatoren, Arbeiten mit Dateien, Metadaten).
0. Erste Schritte¶
Den Training-Codespace öffnen¶
Falls du das noch nicht getan hast, öffne die Trainingsumgebung wie in der Umgebung einrichten beschrieben.
In das Projektverzeichnis wechseln¶
Wechseln wir in das Verzeichnis, in dem sich die Dateien für dieses Tutorial befinden.
Du kannst VSCode so einstellen, dass es sich auf dieses Verzeichnis konzentriert:
Die Materialien ansehen¶
Du findest eine Haupt-Workflow-Datei und eine CSV-Datei namens greetings.csv, die die Eingabe für die Pipeline enthält.
Eine detaillierte Beschreibung der Dateien findest du im Aufwärmen aus Hello Nextflow.
Der Workflow, den wir testen werden, ist eine Teilmenge des Hello-Workflows, der in Hello Workflow erstellt wurde.
Was macht der Hello Nextflow Workflow?
Falls du das Hello Nextflow-Training nicht gemacht hast, hier ein kurzer Überblick darüber, was dieser einfache Workflow tut.
Der Workflow nimmt eine CSV-Datei mit Begrüßungen entgegen, führt vier aufeinanderfolgende Transformationsschritte durch und gibt eine einzelne Textdatei aus, die ein ASCII-Bild einer lustigen Figur enthält, die die Begrüßungen sagt.
Die vier Schritte sind als Nextflow-Prozesse implementiert (sayHello, convertToUpper, collectGreetings und cowpy), die in separaten Moduldateien gespeichert sind.
sayHello: Schreibt jede Begrüßung in eine eigene Ausgabedatei (z. B. "Hello-output.txt")convertToUpper: Konvertiert jede Begrüßung in Großbuchstaben (z. B. "HELLO")collectGreetings: Sammelt alle Begrüßungen in Großbuchstaben in einer einzigen Batch-Dateicowpy: Generiert ASCII-Art mit demcowpy-Tool
Die Ergebnisse werden in einem Verzeichnis namens results/ veröffentlicht, und die endgültige Ausgabe der Pipeline (bei Ausführung mit Standardparametern) ist eine Nur-Text-Datei mit ASCII-Art einer Figur, die die Begrüßungen in Großbuchstaben sagt.
In dieser Side Quest verwenden wir eine Zwischenform des Hello-Workflows, die nur die ersten beiden Prozesse enthält.
Die Teilmenge, mit der wir arbeiten werden, besteht aus zwei Prozessen: sayHello und convertToUpper.
Den vollständigen Workflow-Code siehst du unten.
Workflow-Code
/*
* Pipeline-Parameter
*/
params.input_file = "greetings.csv"
/*
* Verwende echo, um 'Hello World!' auf die Standardausgabe zu schreiben
*/
process sayHello {
publishDir 'results', mode: 'copy'
input:
val greeting
output:
path "${greeting}-output.txt"
script:
"""
echo '$greeting' > '$greeting-output.txt'
"""
}
/*
* Verwende ein Textersetzungs-Utility, um die Begrüßung in Großbuchstaben umzuwandeln
*/
process convertToUpper {
publishDir 'results', mode: 'copy'
input:
path input_file
output:
path "UPPER-${input_file}"
script:
"""
cat '$input_file' | tr '[a-z]' '[A-Z]' > UPPER-${input_file}
"""
}
workflow {
// Erstelle einen Kanal für Eingaben aus einer CSV-Datei
greeting_ch = channel.fromPath(params.input_file).splitCsv().flatten()
// Eine Begrüßung ausgeben
sayHello(greeting_ch)
// Die Begrüßung in Großbuchstaben umwandeln
convertToUpper(sayHello.out)
}
Den Workflow ausführen¶
Führen wir den Workflow aus, um sicherzustellen, dass er wie erwartet funktioniert.
N E X T F L O W ~ version 24.10.2
Launching `main.nf` [soggy_linnaeus] DSL2 - revision: bbf79d5c31
executor > local (6)
[f7/c3be66] sayHello (3) | 3 of 3 ✔
[cd/e15303] convertToUpper (3) | 3 of 3 ✔
HERZLICHEN GLÜCKWUNSCH! Du hast gerade einen Test durchgeführt!
„Moment mal? Ich habe doch nur den Workflow ausgeführt und er hat funktioniert! Wie ist das ein Test?"
Gute Frage!
Lass uns aufschlüsseln, was gerade passiert ist.
Du hast den Workflow mit den Standardparametern ausgeführt, bestätigt, dass er funktioniert, und bist mit den Ergebnissen zufrieden. Das ist das Wesen des Testens. Wenn du den Hello Nextflow-Trainingskurs durchgearbeitet hast, wirst du bemerkt haben, dass wir jeden Abschnitt immer damit begonnen haben, den Workflow auszuführen, den wir als Ausgangspunkt verwendet haben, um zu bestätigen, dass alles korrekt eingerichtet ist.
Das Testen von Software macht diesen Prozess im Wesentlichen für uns.
Die Aufgabe ansehen¶
Deine Herausforderung besteht darin, diesem Workflow mit nf-test standardisierte Tests hinzuzufügen, damit es einfach ist zu überprüfen, ob jeder Teil weiterhin wie erwartet funktioniert, falls weitere Änderungen vorgenommen werden.
Bereitschafts-Checkliste¶
Denkst du, du bist bereit loszulegen?
- Ich verstehe das Ziel dieses Kurses und seine Voraussetzungen
- Mein Codespace läuft
- Ich habe mein Arbeitsverzeichnis entsprechend eingestellt
- Ich habe den Workflow erfolgreich ausgeführt
- Ich verstehe die Aufgabe
Wenn du alle Punkte abhaken kannst, kann es losgehen.
1. nf-test initialisieren¶
Das nf-test-Paket bietet einen Initialisierungsbefehl, der einige Dinge einrichtet, damit wir mit der Entwicklung von Tests für unser Projekt beginnen können.
Dies sollte folgende Ausgabe erzeugen:
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Project configured. Configuration is stored in nf-test.config
Es wird auch ein tests-Verzeichnis mit einer Konfigurationsdatei-Vorlage erstellt.
1.1. Einen nf-test generieren¶
nf-test enthält eine Reihe von Tools zum Erstellen von nf-test-Dateien, die uns den Großteil der Arbeit abnehmen. Diese sind unter dem Unterbefehl generate verfügbar. Lass uns einen Test für die Pipeline generieren:
> nf-test generate pipeline main.nf
Load source file '/workspaces/training/side-quests/nf-test/main.nf'
Wrote pipeline test file '/workspaces/training/side-quests/nf-test/tests/main.nf.test
SUCCESS: Generated 1 test files.
Dadurch wird eine main.nf.test-Datei im tests-Verzeichnis erstellt. Das ist unsere Test-Datei auf Pipeline-Ebene. Wenn du tree tests/ ausführst, solltest du etwas wie das hier sehen:
Die main.nf.test-Datei ist unsere Test-Datei auf Pipeline-Ebene. Öffnen wir sie und schauen uns den Inhalt an.
nextflow_pipeline {
name "Test Workflow main.nf"
script "main.nf"
test("Should run without failures") {
when {
params {
// Parameter hier definieren. Beispiel:
// outdir = "tests/results"
}
}
then {
assert workflow.success
}
}
}
Nehmen wir uns einen Moment, um die Struktur der Test-Datei zu verstehen.
Der nextflow_pipeline-Block ist der Einstiegspunkt für alle Tests auf Pipeline-Ebene. Er enthält Folgendes:
name: Der Name des Tests.script: Der Pfad zum Pipeline-Skript.
Der test-Block ist der eigentliche Test. Er enthält Folgendes:
when: Die Bedingungen, unter denen der Test ausgeführt werden soll. Dazu gehören die Parameter, die zum Ausführen der Pipeline verwendet werden.then: Die Assertions, die gemacht werden sollen. Dazu gehören die erwarteten Ergebnisse der Pipeline.
In einfachen Worten lautet die Logik des Tests wie folgt: „Wenn diese Parameter für diese Pipeline angegeben werden, dann erwarten wir diese Ergebnisse."
Das ist noch kein funktionaler Test – wir zeigen im nächsten Abschnitt, wie man ihn in einen solchen umwandelt.
Ein Hinweis zu Test-Namen¶
Im obigen Beispiel haben wir den Standardnamen „Should run without failures" verwendet, der für einen einfachen Test geeignet ist, der nur prüft, ob die Pipeline erfolgreich ausgeführt wird. Wenn wir jedoch spezifischere Testfälle hinzufügen, sollten wir aussagekräftigere Namen verwenden, die angeben, was wir tatsächlich testen. Zum Beispiel:
- „Should convert input to uppercase" – beim Testen spezifischer Funktionalität
- „Should handle empty input gracefully" – beim Testen von Grenzfällen
- „Should respect max memory parameter" – beim Testen von Ressourcenbeschränkungen
- „Should create expected output files" – beim Testen der Dateigenerierung
Gute Test-Namen sollten:
- Mit „Should" beginnen, um deutlich zu machen, was das erwartete Verhalten ist
- Die spezifische Funktionalität oder das getestete Szenario beschreiben
- Klar genug sein, dass du weißt, welche Funktionalität defekt ist, wenn der Test fehlschlägt
Wenn wir später weitere Assertions und spezifische Testfälle hinzufügen, werden wir diese aussagekräftigeren Namen verwenden, um deutlich zu machen, was jeder Test überprüft.
1.2. Den Test ausführen¶
Führen wir den Test aus, um zu sehen, was passiert.
> nf-test test tests/main.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Workflow main.nf
Test [693ba951] 'Should run without failures' FAILED (4.652s)
Assertion failed:
assert workflow.success
| |
workflow false
Nextflow stdout:
ERROR ~ No such file or directory: /workspaces/training/side-quests/nf-test/.nf-test/tests/693ba951a20fec36a5a9292ed1cc8a9f/greetings.csv
-- Check '/workspaces/training/side-quests/nf-test/.nf-test/tests/693ba951a20fec36a5a9292ed1cc8a9f/meta/nextflow.log' file for details
Nextflow stderr:
FAILURE: Executed 1 tests in 4.679s (1 failed)
Der Test schlägt fehl! Was ist passiert?
- nf-test hat versucht, die Pipeline so auszuführen, wie sie ist, mit den Einstellungen im
when-Block:
when {
params {
// Parameter hier definieren. Beispiel:
// outdir = "tests/results"
}
}
- nf-test hat den Status der Pipeline überprüft und ihn mit dem
when-Block verglichen:
Beachte, wie nf-test gemeldet hat, dass die Pipeline fehlgeschlagen ist, und die Fehlermeldung von Nextflow bereitgestellt hat:
ERROR ~ No such file or directory: /workspaces/training/side-quests/nf-test/.nf-test/tests/693ba951a20fec36a5a9292ed1cc8a9f/greetings.csv
Was war also das Problem? Denk daran, dass die Pipeline eine greetings.csv-Datei im Projektverzeichnis hat. Wenn nf-test die Pipeline ausführt, sucht es nach dieser Datei, kann sie aber nicht finden. Die Datei ist vorhanden – was passiert also? Wenn wir uns den Pfad ansehen, können wir sehen, dass der Test im Pfad ./nf-test/tests/longHashString/ stattfindet. Genau wie Nextflow erstellt nf-test für jeden Test ein neues Verzeichnis, um alles isoliert zu halten. Die Datendatei befindet sich nicht dort, also müssen wir den Pfad zur Datei im ursprünglichen Test korrigieren.
Gehen wir zurück zur Test-Datei und ändern den Pfad zur Datei im when-Block.
Du fragst dich vielleicht, wie wir im Test auf das Stammverzeichnis der Pipeline zeigen sollen. Da dies eine häufige Situation ist, hat nf-test eine Reihe von globalen Variablen, die wir verwenden können, um uns das Leben zu erleichtern. Die vollständige Liste findest du hier, aber vorerst verwenden wir die Variable projectDir, die das Stammverzeichnis des Pipeline-Projekts bezeichnet.
Führen wir den Test erneut aus, um zu sehen, ob er funktioniert.
> nf-test test tests/main.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Workflow main.nf
Test [1d4aaf12] 'Should run without failures' PASSED (1.619s)
SUCCESS: Executed 1 tests in 1.626s
Erfolg! Die Pipeline wird erfolgreich ausgeführt und der Test besteht. Führe ihn so oft aus, wie du möchtest – du wirst immer das gleiche Ergebnis erhalten!
Standardmäßig ist die Nextflow-Ausgabe ausgeblendet, aber um dich zu überzeugen, dass nf-test den Workflow tatsächlich ausführt, kannst du das --verbose-Flag verwenden:
> nf-test test tests/main.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Workflow main.nf
Test [693ba951] 'Should run without failures'
> Nextflow 24.10.4 is available - Please consider updating your version to it
> N E X T F L O W ~ version 24.10.0
> Launching `/workspaces/training/side-quests/nf-test/main.nf` [zen_ampere] DSL2 - revision: bbf79d5c31
> [2b/61e453] Submitted process > sayHello (2)
> [31/4e1606] Submitted process > sayHello (1)
> [bb/5209ee] Submitted process > sayHello (3)
> [83/83db6f] Submitted process > convertToUpper (2)
> [9b/3428b1] Submitted process > convertToUpper (1)
> [ca/0ba51b] Submitted process > convertToUpper (3)
PASSED (5.206s)
SUCCESS: Executed 1 tests in 5.239s
1.3. Assertions hinzufügen¶
Eine einfache Überprüfung besteht darin, sicherzustellen, dass unsere Pipeline alle erwarteten Prozesse ausführt und keinen stillschweigend überspringt. Denk daran, dass unsere Pipeline 6 Prozesse ausführt: einen namens sayHello und einen namens convertToUpper für jede der 3 Begrüßungen.
Fügen wir unserer Test-Datei eine Assertion hinzu, um zu überprüfen, ob die Pipeline die erwartete Anzahl von Prozessen ausführt. Wir aktualisieren auch unseren Test-Namen, um besser widerzuspiegeln, was wir testen.
Der Test-Name spiegelt jetzt besser wider, was wir tatsächlich überprüfen – nicht nur, dass die Pipeline ohne Fehler läuft, sondern dass sie die erwartete Anzahl von Prozessen ausführt.
Führen wir den Test erneut aus, um zu sehen, ob er funktioniert.
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Workflow main.nf
Test [1d4aaf12] 'Should run successfully with correct number of processes' PASSED (1.567s)
SUCCESS: Executed 1 tests in 1.588s
Erfolg! Die Pipeline wird erfolgreich ausgeführt und der Test besteht. Jetzt haben wir begonnen, die Details der Pipeline zu testen, nicht nur den Gesamtstatus.
1.4. Die Ausgabe testen¶
Fügen wir unserer Test-Datei eine Assertion hinzu, um zu überprüfen, ob die Ausgabedatei erstellt wurde. Wir fügen sie als separaten Test mit einem aussagekräftigen Namen hinzu, um die Ergebnisse leichter interpretierbar zu machen.
Führe den Test erneut aus, um zu sehen, ob er funktioniert.
> nf-test test tests/main.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Workflow main.nf
Test [f0e08a68] 'Should run successfully with correct number of processes' PASSED (8.144s)
Test [d7e32a32] 'Should produce correct output files' PASSED (6.994s)
SUCCESS: Executed 2 tests in 15.165s
Erfolg! Die Tests bestehen, weil die Pipeline erfolgreich abgeschlossen wurde, die korrekte Anzahl von Prozessen ausgeführt wurde und die Ausgabedateien erstellt wurden. Das zeigt dir auch, wie nützlich es ist, aussagekräftige Namen für deine Tests zu vergeben.
Das ist nur die Oberfläche – wir können weiterhin Assertions schreiben, um die Details der Pipeline zu überprüfen, aber für jetzt gehen wir weiter zum Testen der Pipeline-Interna.
Fazit¶
Du weißt jetzt, wie man einen nf-test für eine Pipeline schreibt.
Wie geht es weiter?¶
Lerne, wie man einen Nextflow-Prozess testet.
2. Einen Nextflow-Prozess testen¶
Wir müssen nicht für jeden Teil der Pipeline Tests schreiben, aber je mehr Tests wir haben, desto umfassender können wir die Pipeline abdecken und desto sicherer können wir sein, dass sie wie erwartet funktioniert. In diesem Abschnitt werden wir beide Prozesse in der Pipeline als einzelne Einheiten testen.
2.1. Den sayHello-Prozess testen¶
Beginnen wir mit dem sayHello-Prozess.
Verwenden wir erneut den Befehl nf-test generate, um Tests für den Prozess zu generieren.
> nf-test generate process main.nf
Load source file '/workspaces/training/side-quests/nf-test/main.nf'
Wrote process test file '/workspaces/training/side-quests/nf-test/tests/main.sayhello.nf.test
Wrote process test file '/workspaces/training/side-quests/nf-test/tests/main.converttoupper.nf.test
SUCCESS: Generated 2 test files.
Konzentrieren wir uns zunächst auf den sayhello-Prozess in der Datei main.sayhello.nf.test.
Öffnen wir die Datei und schauen uns den Inhalt an.
nextflow_process {
name "Test Process sayHello"
script "main.nf"
process "sayHello"
test("Should run without failures") {
when {
params {
// Parameter hier definieren. Beispiel:
// outdir = "tests/results"
}
process {
"""
// Eingaben des Prozesses hier definieren. Beispiel:
// input[0] = file("test-file.txt")
"""
}
}
then {
assert process.success
assert snapshot(process.out).match()
}
}
}
Wie zuvor beginnen wir mit den Test-Details, gefolgt von den when- und then-Blöcken. Wir haben jedoch auch einen zusätzlichen process-Block, der es uns ermöglicht, die Eingaben für den Prozess zu definieren.
Führen wir den Test aus, um zu sehen, ob er funktioniert.
> nf-test test tests/main.sayhello.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Process sayHello
Test [1eaad118] 'Should run without failures' FAILED (4.876s)
Assertion failed:
assert process.success
| |
| false
sayHello
Nextflow stdout:
Process `sayHello` declares 1 input but was called with 0 arguments
Nextflow stderr:
FAILURE: Executed 1 tests in 4.884s (1 failed)
Der Test schlägt fehl, weil der sayHello-Prozess 1 Eingabe deklariert, aber mit 0 Argumenten aufgerufen wurde. Beheben wir das, indem wir eine Eingabe für den Prozess hinzufügen. Denk daran aus Hello Workflow (und dem Aufwärm-Abschnitt oben), dass unser sayHello-Prozess eine einzelne Wert-Eingabe nimmt, die wir angeben müssen. Wir sollten auch den Test-Namen korrigieren, um besser widerzuspiegeln, was wir testen.
| tests/main.sayhello.nf.test | |
|---|---|
Führen wir den Test erneut aus, um zu sehen, ob er funktioniert.
> nf-test test tests/main.sayhello.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Process sayHello
Test [f91a1bcd] 'Should run without failures and produce correct output' PASSED (1.604s)
Snapshots:
1 created [Should run without failures and produce correct output]
Snapshot Summary:
1 created
SUCCESS: Executed 1 tests in 1.611s
Erfolg! Der Test besteht, weil der sayHello-Prozess erfolgreich ausgeführt wurde und die Ausgabe erstellt wurde.
2.2. Den vom Test erstellten Snapshot ansehen¶
Wenn wir uns die Datei tests/main.sayhello.nf.test ansehen, können wir sehen, dass sie eine Methode snapshot() im Assertion-Block verwendet:
Dies weist nf-test an, einen Snapshot der Ausgabe des sayHello-Prozesses zu erstellen. Schauen wir uns den Inhalt der Snapshot-Datei an.
Wir drucken es hier nicht aus, aber du solltest eine JSON-Datei sehen, die Details des Prozesses und der Prozessausgaben enthält. Insbesondere können wir eine Zeile sehen, die so aussieht:
Dies repräsentiert die vom sayHello-Prozess erstellten Ausgaben, die wir explizit testen. Wenn wir den Test erneut ausführen, prüft das Programm, ob die neue Ausgabe mit der ursprünglich aufgezeichneten Ausgabe übereinstimmt. Das ist eine schnelle, einfache Möglichkeit zu testen, dass sich Prozessausgaben nicht ändern, weshalb nf-test es als Standard bereitstellt.
Warnung
Das bedeutet, dass wir sicherstellen müssen, dass die Ausgabe, die wir beim ursprünglichen Durchlauf aufzeichnen, korrekt ist!
Wenn sich im Laufe der weiteren Entwicklung etwas im Code ändert, das dazu führt, dass die Ausgabe anders ist, schlägt der Test fehl und wir müssen bestimmen, ob die Änderung erwartet wurde oder nicht.
- Wenn sich herausstellt, dass etwas im Code kaputt gegangen ist, müssen wir es reparieren, mit der Erwartung, dass der reparierte Code den Test besteht.
- Wenn es eine erwartete Änderung ist (z. B. das Tool wurde verbessert und die Ergebnisse sind besser), müssen wir den Snapshot aktualisieren, um die neue Ausgabe als Referenz zu akzeptieren. nf-test hat dafür den Parameter
--update-snapshot.
Wir können den Test erneut ausführen und sehen, dass er bestehen sollte:
> nf-test test tests/main.sayhello.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Process sayHello
Test [f91a1bcd] 'Should run without failures and produce correct output' PASSED (1.675s)
SUCCESS: Executed 1 tests in 1.685s
Erfolg! Der Test besteht, weil der sayHello-Prozess erfolgreich ausgeführt wurde und die Ausgabe mit dem Snapshot übereinstimmt.
2.3. Alternative zu Snapshots: Direkte Inhalts-Assertions¶
Während Snapshots gut darin sind, Änderungen in der Ausgabe zu erkennen, möchtest du manchmal spezifische Inhalte überprüfen, ohne so streng zu sein, dass die gesamte Datei übereinstimmen muss. Zum Beispiel:
- Wenn Teile der Ausgabe sich ändern können (Zeitstempel, zufällige IDs usw.), aber bestimmte Schlüsselinhalte vorhanden sein müssen
- Wenn du nach bestimmten Mustern oder Werten in der Ausgabe suchen möchtest
- Wenn du den Test expliziter darüber machen möchtest, was Erfolg ausmacht
So könnten wir unseren Test ändern, um spezifische Inhalte zu überprüfen:
| tests/main.sayhello.nf.test | |
|---|---|
Beachte, dass nf-test die Prozessausgaben als Liste von Listen betrachtet, sodass process.out[0][0] den ersten Teil des ersten Kanal-Elements (oder der ersten „Emission") dieses Prozesses abruft.
Dieser Ansatz:
- Macht deutlich, was wir in der Ausgabe erwarten
- Ist widerstandsfähiger gegenüber irrelevanten Änderungen in der Ausgabe
- Liefert bessere Fehlermeldungen, wenn Tests fehlschlagen
- Ermöglicht komplexere Validierungen (regex-Muster, numerische Vergleiche usw.)
Führen wir den Test aus, um zu sehen, ob er funktioniert.
> nf-test test tests/main.sayhello.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Process sayHello
Test [58df4e4b] 'Should run without failures and contain expected greeting' PASSED (7.196s)
SUCCESS: Executed 1 tests in 7.208s
2.4. Den convertToUpper-Prozess testen¶
Öffnen wir die Datei tests/main.converttoupper.nf.test und schauen uns den Inhalt an:
nextflow_process {
name "Test Process convertToUpper"
script "main.nf"
process "convertToUpper"
test("Should run without failures") {
when {
params {
// Parameter hier definieren. Beispiel:
// outdir = "tests/results"
}
process {
"""
// Eingaben des Prozesses hier definieren. Beispiel:
// input[0] = file("test-file.txt")
"""
}
}
then {
assert process.success
assert snapshot(process.out).match()
}
}
}
Das ist ein ähnlicher Test wie beim sayHello-Prozess, aber er testet den convertToUpper-Prozess. Wir wissen, dass dieser fehlschlagen wird, weil genau wie bei sayHello der convertToUpper-Prozess eine einzelne Pfad-Eingabe nimmt, die wir aber noch nicht angegeben haben.
Wir müssen jetzt eine einzelne Eingabedatei für den convertToUpper-Prozess bereitstellen, die Text enthält, den wir in Großbuchstaben umwandeln möchten. Es gibt viele Möglichkeiten, dies zu tun:
- Wir könnten eine dedizierte Datei zum Testen erstellen
- Wir könnten die vorhandene
data/greetings.csv-Datei wiederverwenden - Wir könnten sie im Test spontan erstellen
Für jetzt verwenden wir die vorhandene data/greetings.csv-Datei mit dem Beispiel, das wir beim Test auf Pipeline-Ebene verwendet haben. Wie zuvor können wir den Test benennen, um besser widerzuspiegeln, was wir testen, aber dieses Mal lassen wir es den Inhalt per Snapshot erfassen, anstatt nach bestimmten Strings zu suchen (wie wir es beim anderen Prozess getan haben).
| tests/main.converttoupper.nf.test | |
|---|---|
Und den Test ausführen!
> nf-test test tests/main.converttoupper.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Process convertToUpper
Test [c59b6044] 'Should run without failures and produce correct output' PASSED (1.755s)
Snapshots:
1 created [Should run without failures and produce correct output]
Snapshot Summary:
1 created
SUCCESS: Executed 1 tests in 1.764s
Beachte, dass wir eine Snapshot-Datei für den convertToUpper-Prozess unter tests/main.converttoupper.nf.test.snap erstellt haben. Wenn wir den Test erneut ausführen, sollten wir sehen, dass nf-test wieder besteht.
> nf-test test tests/main.converttoupper.nf.test
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Process convertToUpper
Test [c59b6044] 'Should run without failures and produce correct output' PASSED (1.798s)
SUCCESS: Executed 1 tests in 1.811s
Fazit¶
Du weißt jetzt, wie man Tests für einen Nextflow-Prozess schreibt und ausführt.
Wie geht es weiter?¶
Lerne, wie man Tests für alles auf einmal ausführt!
3. Tests für das gesamte Repository ausführen¶
nf-test für jede Komponente einzeln auszuführen ist in Ordnung, aber mühsam und fehleranfällig. Können wir nicht einfach alles auf einmal testen?
Ja, das können wir!
Führen wir nf-test für das gesamte Repository aus.
3.1. nf-test für das gesamte Repository ausführen¶
Wir können nf-test für das gesamte Repository ausführen, indem wir den Befehl nf-test test verwenden.
Beachte, dass wir einfach . verwenden, um alles aus unserem aktuellen Verzeichnis auszuführen. Das schließt jeden Test ein!
> nf-test test .
🚀 nf-test 0.9.3
https://www.nf-test.com
(c) 2021 - 2024 Lukas Forer and Sebastian Schoenherr
Test Process convertToUpper
Test [3d26d9af] 'Should run without failures and produce correct output' PASSED (4.155s)
Test Workflow main.nf
Test [f183df37] 'Should run successfully with correct number of processes' PASSED (3.33s)
Test [d7e32a32] 'Should produce correct output files' PASSED (3.102s)
Test Process sayHello
Test [58df4e4b] 'Should run without failures and contain expected greeting' PASSED (2.614s)
SUCCESS: Executed 4 tests in 13.481s
Schau dir das an! Wir haben 4 Tests ausgeführt – 1 für jeden Prozess und 2 für die gesamte Pipeline – mit einem einzigen Befehl. Stell dir vor, wie mächtig das bei einer großen Codebasis ist!
Zusammenfassung¶
In dieser Side Quest hast du gelernt, die Funktionen von nf-test zu nutzen, um Tests für einzelne Prozesse sowie End-to-End-Tests für die gesamte Pipeline zu erstellen und auszuführen. Du kennst jetzt die beiden Hauptansätze zur Ausgabevalidierung – Snapshots und direkte Inhalts-Assertions – und weißt, wann du welchen verwenden solltest. Du weißt auch, wie man Tests einzeln oder für ein gesamtes Projekt ausführt.
Die Anwendung dieser Techniken in deiner eigenen Arbeit ermöglicht es dir sicherzustellen, dass:
- Dein Code wie erwartet funktioniert
- Änderungen keine bestehende Funktionalität beeinträchtigen
- Andere Entwickler*innen mit Vertrauen beitragen können
- Probleme schnell identifiziert und behoben werden können
- Ausgabeinhalte den Erwartungen entsprechen
Wichtige Muster¶
- Tests auf Pipeline-Ebene:
- Grundlegendes Erfolgs-Testing
- Überprüfung der Prozessanzahl
- Überprüfung der Existenz von Ausgabedateien
- Tests auf Prozessebene
- Zwei Ansätze zur Ausgabevalidierung:
- Verwendung von Snapshots für die vollständige Ausgabeüberprüfung
- Verwendung direkter Inhalts-Assertions für spezifische Inhaltsüberprüfungen
- Ausführen aller Tests in einem Repository mit einem einzigen Befehl
Weitere Ressourcen¶
Schau dir die nf-test-Dokumentation für erweiterte Test-Funktionen und Best Practices an. Vielleicht möchtest du:
- Umfassendere Assertions zu deinen Tests hinzufügen
- Tests für Grenzfälle und Fehlerbedingungen schreiben
- Continuous Integration einrichten, um Tests automatisch auszuführen
- Mehr über andere Testtypen wie Workflow- und Modultests erfahren
- Fortgeschrittenere Inhaltsvalidierungstechniken erkunden
Denk daran: Tests sind lebendige Dokumentation darüber, wie sich dein Code verhalten soll. Je mehr Tests du schreibst und je spezifischer deine Assertions sind, desto sicherer kannst du dir bei der Zuverlässigkeit deiner Pipeline sein.
Wie geht es weiter?¶
Kehre zum Menü der Side Quests zurück oder klicke auf die Schaltfläche unten rechts auf der Seite, um zum nächsten Thema in der Liste zu wechseln.