Zum Inhalt springen

Tests schreiben

Entwicklung und Testen

Es ist entscheidend, dass jede neue Funktion korrekte Tests hat, die nicht nur den „Happy Path“ prüfen, sondern auch Randfälle und die fehlerhafte Verwendung der Funktion. In diesem Abschnitt beschreiben wir, wie DuckDB-Tests aufgebaut sind und wie Sie neue Tests für DuckDB anlegen.

Die Tests können ausgeführt werden, indem Sie das Programm unittest im Ordner test starten. Bei den Standard-Kompilierungen liegt es entweder in build/release/test/unittest (Release) oder build/debug/test/unittest (Debug).

Philosophie

Beim Testen von DuckDB zielen wir darauf ab, alle Tests über SQL zu führen. Wir versuchen zu vermeiden, Komponenten einzeln zu testen, weil das spätere Änderungen an diesen Komponenten erschwert. Deshalb können (und sollten) fast alle unsere Tests in reinem SQL ausgedrückt werden. Es gibt bestimmte Ausnahmen davon, die wir in Catch-Tests behandeln. In den meisten Fällen sollten Sie Ihre Tests jedoch in reinem SQL schreiben.

Frameworks

SQL-Tests sollten mit dem sqllogictest-Framework geschrieben werden.

C++-Tests können mit dem Catch-Framework geschrieben werden.

Client-Connector-Tests

DuckDB hat außerdem Tests für verschiedene Client-Connectors. Diese sind in der Regel in der jeweiligen Clientsprache geschrieben und liegen in tools/*/tests. Sie dienen zugleich als Dokumentation dessen, was von einem gegebenen Client aus möglich sein sollte.

Funktionen zum Erzeugen von Testdaten

DuckDB hat eingebaute Funktionen zum Erzeugen von Testdaten.

Die Funktion test_all_types

Die Tabellenfunktion test_all_types erzeugt eine Tabelle, deren Spalten Typen entsprechen (BOOL, TINYINT usw.). Die Tabelle hat drei Zeilen, die den Minimalwert, den Maximalwert und den NULL-Wert für jeden Typ kodieren.

FROM test_all_types();
┌─────────┬─────────┬──────────┬─────────────┬──────────────────────┬──────────────────────┬───┬──────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┐
│ bool │ tinyint │ smallint │ int │ bigint │ hugeint │ … │ struct │ struct_of_arrays │ array_of_structs │ map │ union │
│ boolean │ int8 │ int16 │ int32 │ int64 │ int128 │ │ struct(a integer, … │ struct(a integer[]… │ struct(a integer, … │ map(varchar, varch… │ union("name" varch… │
├─────────┼─────────┼──────────┼─────────────┼──────────────────────┼──────────────────────┼───┼──────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ false │ -128 │ -32768 │ -2147483648 │ -9223372036854775808 │ -17014118346046923… │ … │ {'a': NULL, 'b': N… │ {'a': NULL, 'b': N… │ [] │ {} │ Frank │
│ true │ 127 │ 32767 │ 2147483647 │ 9223372036854775807 │ 170141183460469231… │ … │ {'a': 42, 'b': 🦆… │ {'a': [42, 999, NU… │ [{'a': NULL, 'b': … │ {key1=🦆🦆🦆🦆🦆🦆… │ 5 │
│ NULL │ NULL │ NULL │ NULL │ NULL │ NULL │ … │ NULL │ NULL │ NULL │ NULL │ NULL │
├─────────┴─────────┴──────────┴─────────────┴──────────────────────┴──────────────────────┴───┴──────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┤
│ 3 rows 44 columns (11 shown) │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

Die Funktion test_vector_types

Die Tabellenfunktion test_vector_types nimmt n Argumente col1, …, coln und ein optionales Argument all_flat vom Typ BOOLEAN entgegen. Die Funktion erzeugt eine Tabelle mit n Spalten test_vector, test_vector2, …, test_vectorn. In jeder Zeile enthält jedes Feld Werte, die dem Typ der jeweiligen Spalte entsprechen.

FROM test_vector_types(NULL::BIGINT);
┌──────────────────────┐
│ test_vector │
│ int64 │
├──────────────────────┤
│ -9223372036854775808 │
│ 9223372036854775807 │
│ NULL │
│ ... │
└──────────────────────┘
FROM test_vector_types(NULL::ROW(i INTEGER, j VARCHAR, k DOUBLE), NULL::TIMESTAMP);
┌──────────────────────────────────────────────────────────────────────┬──────────────────────────────┐
│ test_vector │ test_vector2 │
│ struct(i integer, j varchar, k double) │ timestamp │
├──────────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ {'i': -2147483648, 'j': 🦆🦆🦆🦆🦆🦆, 'k': -1.7976931348623157e+308} │ 290309-12-22 (BC) 00:00:00 │
│ {'i': 2147483647, 'j': goo\0se, 'k': 1.7976931348623157e+308} │ 294247-01-10 04:00:54.775806 │
│ {'i': NULL, 'j': NULL, 'k': NULL} │ NULL │
│ ... │
└─────────────────────────────────────────────────────────────────────────────────────────────────────┘

test_vector_types hat ein optionales Argument namens all_flat vom Typ BOOL. Das beeinflusst nur die interne Darstellung des Vektors.

FROM test_vector_types(NULL::ROW(i INTEGER, j VARCHAR, k DOUBLE), NULL::TIMESTAMP, all_flat = true);
-- the output is the same as above but with a different internal representation