Framework de Testes
Framework de Testes
Seção intitulada “Framework de Testes”O modulo wippy/test fornece um framework de testes estilo BDD com assercoes, hooks de ciclo de vida e mocking.
Configuracao
Seção intitulada “Configuracao”Adicione a dependencia:
wippy add wippy/testwippy installO modulo registra um comando test automaticamente. Uma vez instalado, wippy run test descobre e executa todas as entradas de teste no seu projeto.
Definindo Testes
Seção intitulada “Definindo Testes”Testes sao entradas function.lua com meta.type: test:
version: "1.0"namespace: app.test
entries: - name: math kind: function.lua meta: type: test suite: math name: Operacoes matematicas source: file://math_test.lua method: run imports: test: wippy.test:testMetadados do Teste
Seção intitulada “Metadados do Teste”| Campo | Obrigatorio | Descricao |
|---|---|---|
type | Sim | Deve ser "test" para que o runner o descubra |
suite | Nao | Agrupa testes na saida do runner |
name | Nao | Nome exibido na saida do runner |
order | Nao | Ordem de execucao dentro de uma suite (menor executa primeiro) |
Escrevendo Testes
Seção intitulada “Escrevendo Testes”Estilo BDD
Seção intitulada “Estilo BDD”Use blocos describe e it para estruturar testes:
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 }Suites Aninhadas
Seção intitulada “Suites Aninhadas”Suites podem ser aninhadas para organizacao:
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)Pulando Testes
Seção intitulada “Pulando Testes”test.it_skip("not implemented yet", function() test.fail("TODO")end)Testes pulados aparecem na saida mas nao contam como falhas.
Aliases de Suite
Seção intitulada “Aliases de Suite”test.spec e test.context sao aliases para test.describe:
test.spec("feature", function() test.context("when valid input", function() test.it("succeeds", function() test.ok(true) end) end)end)Assercoes
Seção intitulada “Assercoes”Igualdade
Seção intitulada “Igualdade”test.eq(actual, expected, msg?) -- actual == expectedtest.neq(actual, expected, msg?) -- actual ~= expectedVeracidade
Seção intitulada “Veracidade”test.ok(val, msg?) -- val is truthytest.fail(msg?) -- unconditional failureVerificacoes de Nil
Seção intitulada “Verificacoes de Nil”test.is_nil(val, msg?) -- val == niltest.not_nil(val, msg?) -- val ~= nilVerificacoes de Tipo
Seção intitulada “Verificacoes de Tipo”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 e Colecoes
Seção intitulada “Strings e Colecoes”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 == expectedComparacoes Numericas
Seção intitulada “Comparacoes Numericas”test.gt(a, b, msg?) -- a > btest.gte(a, b, msg?) -- a >= btest.lt(a, b, msg?) -- a < btest.lte(a, b, msg?) -- a <= bTratamento de Erros
Seção intitulada “Tratamento de Erros”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 nilTodas as assercoes aceitam uma mensagem opcional como ultimo argumento. Em caso de falha, a mensagem e incluida na saida de erro.
Hooks de Ciclo de Vida
Seção intitulada “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)Hooks em suites aninhadas executam em ordem: before_each do pai executa antes do before_each do filho, e after_each do filho executa antes do after_each do pai.
Mocking
Seção intitulada “Mocking”O sistema de mock substitui campos de objetos globais e os restaura automaticamente apos cada teste.
Mock Basico
Seção intitulada “Mock 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 Mock
Seção intitulada “API de Mock”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 mocksCaminhos de mock usam notacao de ponto: "process.send" substitui _G.process.send.
Mocks para process.send automaticamente fazem proxy de mensagens do framework de teste atraves da funcao original, para que o relato de eventos de teste continue funcionando quando process.send esta mockado.
Todos os mocks sao automaticamente restaurados apos cada teste via o hook after_each.
Executando Testes
Seção intitulada “Executando Testes”Executar Todos os Testes
Seção intitulada “Executar Todos os Testes”wippy run testFiltrar por Padrao
Seção intitulada “Filtrar por Padrao”wippy run test mathwippy run test user validationFiltros correspondem a IDs de entradas. Multiplos padroes sao combinados.
Exemplo de Saida
Seção intitulada “Exemplo de Saida”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 | 3msTestes Simples
Seção intitulada “Testes Simples”Para testes que nao precisam do framework BDD, defina uma funcao simples que retorna true ou lanca um erro:
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: - funcsO runner detecta se um teste usa eventos de caso BDD ou retorna um valor simples. Ambos os padroes funcionam com wippy run test.
Estrutura do Projeto
Seção intitulada “Estrutura do Projeto”Um layout tipico de testes:
src/ _index.yaml app.lua test/ _index.yaml # test entries math_test.lua user_test.lua integration_test.luaO _index.yaml de testes define o namespace e as entradas de teste:
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:testRequisitos de Infraestrutura
Seção intitulada “Requisitos de Infraestrutura”O runner de testes precisa de um process.host e terminal.host na sua aplicacao. Estes normalmente ja estao presentes. Se nao, adicione-os:
entries: - name: processes kind: process.host lifecycle: auto_start: true
- name: terminal kind: terminal.host lifecycle: auto_start: trueVeja Tambem
Seção intitulada “Veja Tambem”- Visao Geral do Framework - Uso de modulos do framework
- Referencia CLI - Comandos CLI
- Funcoes - Registro de funcoes