Framework de pruebas :id=framework-de-testing
El módulo wippy/test proporciona suites BDD, aserciones, ganchos del ciclo de vida, simulaciones y un ejecutor para entradas de prueba.
Esta página es una introducción a la API. Sus bloques de Lua, YAML, salida y estructura de proyecto son fragmentos de referencia que se pueden combinar en un proyecto Wippy existente; no forman un único proyecto listo para copiar y ejecutar. Nombres como validate, format_name, db, connect y notify_user representan funciones o módulos de aplicación proporcionados por el objeto de la prueba. Para un ejemplo ejecutable completo, siga Probar una aplicación Wippy.
Configuracion
Agrega la dependencia:
wippy add wippy/test
wippy install
El módulo registra automáticamente el punto de entrada de pruebas (un comando con use_case: test). Una vez instalado, wippy test descubre y ejecuta todas las entradas de prueba del proyecto.
Definir pruebas :id=definir-tests
Las pruebas son entradas function.lua con meta.type: test:
version: "1.0"
namespace: app.test
entries:
- name: math
kind: function.lua
meta:
type: test
suite: math
name: Math operations
source: file://math_test.lua
method: main
imports:
test: wippy.test:test
Metadatos de la prueba :id=metadatos-del-test
| Campo | Obligatorio | Descripción |
|---|---|---|
type |
Sí | Debe ser "test" para que el ejecutor lo descubra |
suite |
No | Agrupa pruebas en la salida del ejecutor |
name |
No | Nombre mostrado en la salida del ejecutor |
order |
No | Orden dentro de una suite (menor se ejecuta primero) |
Escribir pruebas :id=escribir-tests
Estilo BDD
Use bloques describe e it para estructurar las pruebas:
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 result
end
return { run = run }
Suites Anidadas
Las suites pueden anidarse para organizacion:
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)
Omitir pruebas :id=omitir-tests
test.it_skip("not implemented yet", function()
test.fail("TODO")
end)
Las pruebas omitidas aparecen en la salida pero no cuentan como fallos.
Alias de Suites
test.spec y test.context son alias de test.describe:
test.spec("feature", function()
test.context("when valid input", function()
test.it("succeeds", function()
test.ok(true)
end)
end)
end)
Aserciones
Igualdad
test.eq(actual, expected, msg?) -- actual == expected
test.neq(actual, expected, msg?) -- actual ~= expected
Veracidad
test.ok(val, msg?) -- val is truthy
test.fail(msg?) -- unconditional failure
Verificaciones de Nil
test.is_nil(val, msg?) -- val == nil
test.not_nil(val, msg?) -- val ~= nil
Verificaciones de Tipo
test.is_true(val, msg?) -- val == true
test.is_false(val, msg?) -- val == false
test.is_string(val, msg?)
test.is_number(val, msg?)
test.is_table(val, msg?)
test.is_function(val, msg?)
test.is_boolean(val, msg?)
Cadenas y colecciones :id=strings-y-colecciones
test.contains(str, substr, msg?) -- substring match
test.matches(str, pattern, msg?) -- Lua pattern match
test.has_key(tbl, key, msg?) -- table key exists
test.len(val, expected, msg?) -- #val == expected
Comparaciones Numericas
test.gt(a, b, msg?) -- a > b
test.gte(a, b, msg?) -- a >= b
test.lt(a, b, msg?) -- a < b
test.lte(a, b, msg?) -- a <= b
Manejo de Errores
test.throws(fn, msg?) -- fn() raises error, returns it
test.has_error(val, err, msg?) -- val is nil, err is not nil
test.no_error(val, err, msg?) -- err is nil
Todas las aserciones aceptan un mensaje opcional como ultimo argumento. En caso de fallo, el mensaje se incluye en la salida de error.
Ganchos del ciclo de vida :id=hooks-de-ciclo-de-vida
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)
Los ganchos de las suites anidadas se ejecutan en orden: el before_each del padre se ejecuta antes del before_each del hijo, y el after_each del hijo se ejecuta antes del after_each del padre.
Simulación :id=mocking
El sistema de simulación reemplaza campos de objetos globales y los restaura automáticamente después de cada prueba.
Simulación básica :id=mocking-basico
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 de simulación :id=api-de-mock
test.mock("object.field", replacement) -- replace a global field
test.mock_process("field", replacement) -- shorthand for process fields
test.restore_mock("object.field") -- restore one mock
test.restore_all_mocks() -- restore all mocks
Las rutas de simulación usan notación de punto: "process.send" reemplaza _G.process.send.
Las simulaciones de process.send redirigen automáticamente los mensajes del framework de pruebas a través de la función original, para que el informe de eventos de prueba siga funcionando cuando process.send está simulado.
Todas las simulaciones se restauran automáticamente después de cada prueba mediante el gancho after_each.
Ejecutar pruebas :id=ejecutar-tests
Ejecutar todas las pruebas :id=ejecutar-todos-los-tests
wippy test
Filtrar por Patron
wippy test math
wippy test user validation
Los filtros comparan substrings literales de los ID de entrada. Con varios patrones, una entrada se ejecuta si su ID coincide con cualquiera de ellos.
Ejemplo de Salida
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
Pruebas simples :id=tests-simples
Para pruebas que no necesitan el framework BDD, defina una función simple que devuelva true o genere un error:
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 true
end
return { main = main }
- name: integration
kind: function.lua
meta:
type: test
suite: integration
source: file://integration_test.lua
method: main
modules:
- funcs
El ejecutor detecta si una prueba usa eventos de casos BDD o devuelve un valor simple. Ambos patrones funcionan con wippy test.
Estructura del Proyecto
Una estructura típica de pruebas:
src/
_index.yaml
app.lua
test/
_index.yaml # test entries
math_test.lua
user_test.lua
integration_test.lua
El _index.yaml de pruebas define el espacio de nombres y las entradas de prueba:
version: "1.0"
namespace: app.test
entries:
- name: math
kind: function.lua
meta:
type: test
suite: math
source: file://math_test.lua
method: main
imports:
test: wippy.test:test
- name: user
kind: function.lua
meta:
type: test
suite: user
source: file://user_test.lua
method: main
imports:
test: wippy.test:test
Host de terminal :id=terminal-host
wippy/test depende de wippy/terminal, que proporciona el wippy.terminal:host de inicio automático usado por el ejecutor de la CLI. Las aplicaciones no necesitan declarar otro host de procesos o de terminal solo para ejecutar wippy test.
Ver Tambien
- Descripción general del framework — Instalar e importar módulos del framework
- Referencia de la CLI — Comando e indicadores de prueba
- Funciones — Entradas de función e invocación