Test-Framework
Test-Framework
Abschnitt betitelt „Test-Framework“Das Modul wippy/test bietet ein BDD-Testframework mit Assertions, Lifecycle-Hooks und Mocking.
Einrichtung
Abschnitt betitelt „Einrichtung“Abhaengigkeit hinzufuegen:
wippy add wippy/testwippy installDas Modul registriert automatisch einen test-Befehl. Nach der Installation erkennt wippy run test alle Test-Eintraege in Ihrem Projekt und fuehrt sie aus.
Tests definieren
Abschnitt betitelt „Tests definieren“Tests sind function.lua-Eintraege mit meta.type: test:
version: "1.0"namespace: app.test
entries: - name: math kind: function.lua meta: type: test suite: math name: Mathematik-Operationen source: file://math_test.lua method: run imports: test: wippy.test:testTest-Metadaten
Abschnitt betitelt „Test-Metadaten“| Field | Required | Beschreibung |
|---|---|---|
type | Yes | Muss "test" sein, damit der Runner den Test erkennt |
suite | No | Gruppiert Tests in der Runner-Ausgabe |
name | No | Anzeigename in der Runner-Ausgabe |
order | No | Sortierreihenfolge innerhalb einer Suite (niedrigere Werte zuerst) |
Tests schreiben
Abschnitt betitelt „Tests schreiben“BDD-Stil
Abschnitt betitelt „BDD-Stil“Verwenden Sie describe- und it-Bloecke zur Strukturierung von Tests:
local test = require("test")
local function define_tests() test.describe("calculator", function() test.it("adds numbers", function() test.eq(1 + 1, 2) end)
test.it("multiplies numbers", function() test.eq(3 * 4, 12) end) end)end
local run_cases = test.run_cases(define_tests)
local function run(options) local result = run_cases(options) if result.failed_tests > 0 then error("tests failed: " .. result.failed_tests) end return resultend
return { run = run }Verschachtelte Suites
Abschnitt betitelt „Verschachtelte Suites“Suites koennen zur Organisation verschachtelt werden:
test.describe("user", function() test.describe("validation", function() test.it("requires name", function() test.ok(validate({}).error) end)
test.it("accepts valid input", function() test.is_nil(validate({name = "Alice"}).error) end) end)
test.describe("formatting", function() test.it("formats display name", function() test.eq(format_name("alice"), "Alice") end) end)end)Tests ueberspringen
Abschnitt betitelt „Tests ueberspringen“test.it_skip("not implemented yet", function() test.fail("TODO")end)Uebersprungene Tests erscheinen in der Ausgabe, zaehlen aber nicht als Fehler.
Suite-Aliase
Abschnitt betitelt „Suite-Aliase“test.spec und test.context sind Aliase fuer test.describe:
test.spec("feature", function() test.context("when valid input", function() test.it("succeeds", function() test.ok(true) end) end)end)Assertions
Abschnitt betitelt „Assertions“Gleichheit
Abschnitt betitelt „Gleichheit“test.eq(actual, expected, msg?) -- actual == expectedtest.neq(actual, expected, msg?) -- actual ~= expectedWahrheitswerte
Abschnitt betitelt „Wahrheitswerte“test.ok(val, msg?) -- val is truthytest.fail(msg?) -- unconditional failureNil-Pruefungen
Abschnitt betitelt „Nil-Pruefungen“test.is_nil(val, msg?) -- val == niltest.not_nil(val, msg?) -- val ~= nilTyppruefungen
Abschnitt betitelt „Typpruefungen“test.is_true(val, msg?) -- val == truetest.is_false(val, msg?) -- val == falsetest.is_string(val, msg?)test.is_number(val, msg?)test.is_table(val, msg?)test.is_function(val, msg?)test.is_boolean(val, msg?)Strings und Collections
Abschnitt betitelt „Strings und Collections“test.contains(str, substr, msg?) -- substring matchtest.matches(str, pattern, msg?) -- Lua pattern matchtest.has_key(tbl, key, msg?) -- table key existstest.len(val, expected, msg?) -- #val == expectedNumerische Vergleiche
Abschnitt betitelt „Numerische Vergleiche“test.gt(a, b, msg?) -- a > btest.gte(a, b, msg?) -- a >= btest.lt(a, b, msg?) -- a < btest.lte(a, b, msg?) -- a <= bFehlerbehandlung
Abschnitt betitelt „Fehlerbehandlung“test.throws(fn, msg?) -- fn() raises error, returns ittest.has_error(val, err, msg?) -- val is nil, err is not niltest.no_error(val, err, msg?) -- err is nilAlle Assertions akzeptieren eine optionale Nachricht als letztes Argument. Bei einem Fehlschlag wird die Nachricht in der Fehlerausgabe angezeigt.
Lifecycle-Hooks
Abschnitt betitelt „Lifecycle-Hooks“test.describe("database", function() test.before_all(function() -- runs once before the suite db = connect() end)
test.after_all(function() -- runs once after the suite db:close() end)
test.before_each(function() -- runs before each test db:begin_transaction() end)
test.after_each(function() -- runs after each test db:rollback() end)
test.it("inserts a record", function() db:exec("INSERT INTO users (name) VALUES ('Alice')") local count = db:query_row("SELECT COUNT(*) FROM users") test.eq(count, 1) end)end)Hooks in verschachtelten Suites werden in Reihenfolge ausgefuehrt: before_each des Eltern-Blocks laeuft vor before_each des Kind-Blocks, und after_each des Kind-Blocks laeuft vor after_each des Eltern-Blocks.
Mocking
Abschnitt betitelt „Mocking“Das Mock-System ersetzt globale Objektfelder und stellt sie nach jedem Test automatisch wieder her.
Einfaches Mocking
Abschnitt betitelt „Einfaches Mocking“test.describe("notifications", function() test.it("sends message", function() local sent = false test.mock("process.send", function(pid, topic, payload) sent = true end)
notify_user("hello") test.is_true(sent) -- mock is auto-restored after this test end)end)Mock-API
Abschnitt betitelt „Mock-API“test.mock("object.field", replacement) -- replace a global fieldtest.mock_process("field", replacement) -- shorthand for process fieldstest.restore_mock("object.field") -- restore one mocktest.restore_all_mocks() -- restore all mocksMock-Pfade verwenden Punkt-Notation: "process.send" ersetzt _G.process.send.
Mocks fuer process.send leiten Test-Framework-Nachrichten automatisch ueber die Originalfunktion weiter, sodass die Test-Event-Berichterstattung weiterhin funktioniert, wenn process.send gemockt ist.
Alle Mocks werden nach jedem Test automatisch ueber den after_each-Hook wiederhergestellt.
Tests ausfuehren
Abschnitt betitelt „Tests ausfuehren“Alle Tests ausfuehren
Abschnitt betitelt „Alle Tests ausfuehren“wippy run testNach Muster filtern
Abschnitt betitelt „Nach Muster filtern“wippy run test mathwippy run test user validationFilter gleichen gegen Entry-IDs ab. Mehrere Muster werden kombiniert.
Beispielausgabe
Abschnitt betitelt „Beispielausgabe“3 tests in 1 suites
calculator + adds numbers 0ms + multiplies numbers 0ms - divides by zero 1ms Error: expected error, got nil
1 suite | 2 passed | 1 failed | 0 skipped | 3msEinfache Tests
Abschnitt betitelt „Einfache Tests“Fuer Tests, die das BDD-Framework nicht benoetigen, definieren Sie eine einfache Funktion, die true zurueckgibt oder einen Fehler ausloest:
local funcs = require("funcs")
local function main() local result, err = funcs.call("app:my_function", "input") if err then error("call failed: " .. tostring(err)) end if result ~= "expected" then error("expected 'expected', got: " .. tostring(result)) end return trueend
return { main = main } - name: integration kind: function.lua meta: type: test suite: integration source: file://integration_test.lua method: main modules: - funcsDer Runner erkennt, ob ein Test BDD-Case-Events verwendet oder einen einfachen Wert zurueckgibt. Beide Muster funktionieren mit wippy run test.
Projektstruktur
Abschnitt betitelt „Projektstruktur“Ein typisches Test-Layout:
src/ _index.yaml app.lua test/ _index.yaml # test entries math_test.lua user_test.lua integration_test.luaDie Test-_index.yaml definiert den Test-Namespace und die Eintraege:
version: "1.0"namespace: app.test
entries: - name: math kind: function.lua meta: type: test suite: math source: file://math_test.lua method: run imports: test: wippy.test:test
- name: user kind: function.lua meta: type: test suite: user source: file://user_test.lua method: run imports: test: wippy.test:testInfrastrukturanforderungen
Abschnitt betitelt „Infrastrukturanforderungen“Der Test-Runner benoetigt einen process.host und terminal.host in Ihrer Anwendung. Diese sind typischerweise bereits vorhanden. Falls nicht, fuegen Sie sie hinzu:
entries: - name: processes kind: process.host lifecycle: auto_start: true
- name: terminal kind: terminal.host lifecycle: auto_start: trueSiehe auch
Abschnitt betitelt „Siehe auch“- Framework-Uebersicht - Verwendung von Framework-Modulen
- CLI-Referenz - CLI-Befehle
- Funktionen - Funktions-Registry