Testing
Testing
Заголовок раздела «Testing»Пишите и запускайте тесты для вашего Lua-кода с помощью фреймворка wippy/test — это
BDD-раннер с ассертами, хуками жизненного цикла и моками, выполняемый командой
wippy run test.
Что вы построите
Заголовок раздела «Что вы построите»Небольшую библиотеку и тестовый набор, который её покрывает:
- Библиотеку
calcс функциямиaddиdiv. - Тестовую запись, которая описывает кейсы, проверяет поведение и пропускает один отложенный кейс.
- Успешный («зелёный») прогон тестов через
wippy run test.
Предварительные требования
Заголовок раздела «Предварительные требования»-
Проект Wippy (склонируйте app-template или выполните
wippy initв пустой директории). -
Установленный тестовый фреймворк и хост терминала:
Окно терминала wippy add wippy/testwippy add wippy/terminalwippy installРаннер отрисовывает живой терминальный UI, поэтому
wippy/terminalтребуется наряду сwippy/test.
Тестируемый код
Заголовок раздела «Тестируемый код»-- src/calc.lualocal function add(a, b) return a + bend
local function div(a, b) if b == 0 then return nil, "division by zero" end return a / bend
return { add = add, div = div }Тест — это обычная запись function.lua, помеченная meta.type: test. Её метод
возвращает значение, полученное от test.run_cases(...), которое вызывает раннер:
-- src/calc_test.lualocal test = require("test")local calc = require("calc")
local function define_tests() test.describe("calculator", function() local started = false
test.before_all(function() started = true end)
test.it("setup ran", function() test.is_true(started) end)
test.it("adds numbers", function() test.eq(calc.add(2, 3), 5) end)
test.it("returns error on divide by zero", function() local result, err = calc.div(1, 0) test.has_error(result, err) test.contains(err, "division by zero") end)
test.it_skip("not implemented yet", function() test.fail("should not run") end) end)end
return { run = test.run_cases(define_tests) }Зарегистрируйте обе записи. Обнаружение тестов опирается на meta.type: test;
meta.suite группирует результаты в выводе:
version: "1.0"namespace: app
entries: - name: calc kind: library.lua source: file://calc.lua
- name: calc_test kind: function.lua meta: name: Calculator Test type: test suite: calculator source: file://calc_test.lua method: run imports: test: wippy.test:test calc: app:calcКарта imports определяет, во что разрешается require(...) внутри теста: test
привязывает фреймворк, calc привязывает тестируемый модуль.
wippy run testОтфильтруйте до одного набора (совпадение по id записи или имени набора) в процессе работы:
wippy run test calculatorВывод для набора выше:
calculator (4) 3/4 1 skipped 1ms o setup ran o adds numbers o returns error on divide by zero - not implemented yet (skipped)
PASSED 3 tests 1 skipped 1mswippy run test завершается с кодом 0, когда все кейсы проходят, и 1 при любом
провале, поэтому команда напрямую встраивается в CI.
Ассерты
Заголовок раздела «Ассерты»Каждый ассерт выбрасывает ошибку при провале; защиты типов также возвращают проверенное значение.
| Ассерт | Что проверяет |
|---|---|
test.eq(a, b) / test.neq(a, b) | Равенство / неравенство |
test.ok(v) / test.fail(msg) | Истинность / принудительный провал |
test.is_nil(v) / test.not_nil(v) | Nil / не-nil |
test.is_true(v) / test.is_false(v) | Логическое значение |
test.is_string/number/table/function/boolean(v) | Защиты типов (возвращают v) |
test.contains(str, sub) / test.matches(str, pattern) | Подстрока / Lua-паттерн |
test.has_key(tbl, key) / test.len(v, n) | Ключ в map / длина |
test.gt/gte/lt/lte(a, b) | Числовое сравнение |
test.throws(fn) / test.has_error(val, err) / test.no_error(val, err) | Обработка ошибок |
Все принимают необязательный завершающий аргумент с сообщением.
Жизненный цикл и моки
Заголовок раздела «Жизненный цикл и моки»Вызывайте их внутри блока describe:
test.before_all/test.after_all— выполняются один раз на блок.test.before_each/test.after_each— выполняются вокруг каждого кейса.test.mock("module.field", fn)— заменяет функцию для текущего кейса; моки восстанавливаются автоматически после каждого кейса. Используйтеtest.restore_all_mocks(), чтобы очистить их заранее.
Вложенные блоки describe наследуют хуки родителя (сначала внешний before_*, сначала
внутренний after_*).
Следующие шаги
Заголовок раздела «Следующие шаги»- Hello World — минимальная структура проекта
- Entry Kinds —
function.lua,library.luaи подобные - Test Framework — полный справочник по раннеру и протоколу событий