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