テストフレームワーク
テストフレームワーク
Section titled “テストフレームワーク”wippy/testモジュールはアサーション、ライフサイクルフック、モッキングを備えたBDDスタイルのテストフレームワークを提供します。
セットアップ
Section titled “セットアップ”依存関係を追加します:
wippy add wippy/testwippy installこのモジュールはtestコマンドを自動的に登録します。インストール後、wippy run testでプロジェクト内の全テストエントリを検出して実行します。
テストの定義
Section titled “テストの定義”テストはmeta.type: testを持つfunction.luaエントリです:
version: "1.0"namespace: app.test
entries: - name: math kind: function.lua meta: type: test suite: math name: 算術演算 source: file://math_test.lua method: run imports: test: wippy.test:testテストメタデータ
Section titled “テストメタデータ”| フィールド | 必須 | 説明 |
|---|---|---|
type | Yes | ランナーが検出するために"test"である必要がある |
suite | No | ランナー出力でテストをグループ化する |
name | No | ランナー出力に表示される表示名 |
order | No | スイート内のソート順(小さい値が先に実行される) |
テストの記述
Section titled “テストの記述”BDDスタイル
Section titled “BDDスタイル”describeとitブロックを使用してテストを構造化します:
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 }ネストされたスイート
Section titled “ネストされたスイート”スイートは整理のためにネストできます:
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)テストのスキップ
Section titled “テストのスキップ”test.it_skip("not implemented yet", function() test.fail("TODO")end)スキップされたテストは出力に表示されますが、失敗としてカウントされません。
スイートエイリアス
Section titled “スイートエイリアス”test.specとtest.contextはtest.describeのエイリアスです:
test.spec("feature", function() test.context("when valid input", function() test.it("succeeds", function() test.ok(true) end) end)end)アサーション
Section titled “アサーション”test.eq(actual, expected, msg?) -- actual == expectedtest.neq(actual, expected, msg?) -- actual ~= expectedtest.ok(val, msg?) -- val is truthytest.fail(msg?) -- unconditional failureNilチェック
Section titled “Nilチェック”test.is_nil(val, msg?) -- val == niltest.not_nil(val, msg?) -- val ~= niltest.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?)文字列とコレクション
Section titled “文字列とコレクション”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 == expectedtest.gt(a, b, msg?) -- a > btest.gte(a, b, msg?) -- a >= btest.lt(a, b, msg?) -- a < btest.lte(a, b, msg?) -- a <= btest.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 nil全てのアサーションは最後の引数としてオプションのメッセージを受け取ります。失敗時にこのメッセージがエラー出力に含まれます。
ライフサイクルフック
Section titled “ライフサイクルフック”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)ネストされたスイートのフックは順番に実行されます: 親のbefore_eachが子のbefore_eachの前に実行され、子のafter_eachが親のafter_eachの前に実行されます。
モックシステムはグローバルオブジェクトのフィールドを置き換え、各テスト後に自動的に復元します。
基本的なモッキング
Section titled “基本的なモッキング”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)モックAPI
Section titled “モック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 mocksモックパスはドット記法を使用します: "process.send"は_G.process.sendを置き換えます。
process.sendのモックは元の関数を通じてテストフレームワークメッセージを自動的にプロキシするため、process.sendがモックされていてもテストイベントレポートは機能し続けます。
全てのモックはafter_eachフックにより各テスト後に自動的に復元されます。
テストの実行
Section titled “テストの実行”全テストの実行
Section titled “全テストの実行”wippy run testパターンによるフィルタ
Section titled “パターンによるフィルタ”wippy run test mathwippy run test user validationフィルタはエントリIDに対してマッチします。複数のパターンは組み合わされます。
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 | 3msシンプルテスト
Section titled “シンプルテスト”BDDフレームワークを必要としないテストの場合、trueを返すかエラーを発生させるシンプルな関数を定義します:
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: - funcsランナーはテストがBDDケースイベントを使用しているか、シンプルな値を返しているかを検出します。両方のパターンがwippy run testで動作します。
プロジェクト構造
Section titled “プロジェクト構造”典型的なテストレイアウト:
src/ _index.yaml app.lua test/ _index.yaml # test entries math_test.lua user_test.lua integration_test.luaテスト用の_index.yamlはテスト名前空間とエントリを定義します:
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:testインフラストラクチャ要件
Section titled “インフラストラクチャ要件”テストランナーはアプリケーションにprocess.hostとterminal.hostが必要です。これらは通常既に存在しています。存在しない場合は追加してください:
entries: - name: processes kind: process.host lifecycle: auto_start: true
- name: terminal kind: terminal.host lifecycle: auto_start: true