Pular para o conteúdo principal

Referência da API de Testes

Referência da API de Testes

O SDK da Turn.io fornece utilitários de teste abrangentes através do módulo turn.test.*. Essas funções permitem que você simule chamadas HTTP, chamadas entre apps e operações assíncronas em seus testes.

Gerenciamento de Estado

turn.test.reset()

Limpa todo o estado de teste e redefine para um estado limpo. Isso é crítico para garantir que os testes não vazem estado uns para os outros.

before(function()
turn.test.reset() -- Comece cada teste limpo
end)

Após chamar reset(), os seguintes dados de teste estão disponíveis:

  • 2 contatos de teste: contact-1 e contact-2
  • 2 jornadas de teste: journey-1 e journey-2

turn.test.set_config(key, value)

Define valores de configuração para teste. Útil para testar com diferentes configurações de app.

turn.test.set_config("api_key", "test-key-123")
turn.test.set_config("webhook_url", "https://test.example.com/webhook")

turn.test.get_config(key)

Recupera um valor de configuração de teste.

local api_key = turn.test.get_config("api_key")
assert(api_key == "test-key-123")

Testes de Configuração

turn.test.set_config(key, value) e turn.test.get_config(key)

Esses métodos permitem que você teste o comportamento do seu app com diferentes configurações sem precisar modificar a configuração real do app.

describe("com configurações diferentes", function()
it("deve usar a chave API de teste", function()
turn.test.reset()
turn.test.set_config("api_key", "test-key-abc")

-- Seu app agora verá esta configuração ao chamar turn.configuration.get()
local result = app:on_event({}, number, "some_event", {})

-- Verificar que usou a chave de teste
turn.test.assert_http_called({
headers = {Authorization = "Bearer test-key-abc"}
})
end)
end)

Simulação de Requisições HTTP

turn.test.mock_http(expected_request, mock_response)

Simula uma chamada HTTP para que seu app não faça requisições de rede reais durante os testes. Isso permite testar offline e garante velocidade e confiabilidade.

turn.test.mock_http(
{
method = "GET",
url = "https://api.example.com/data",
headers = {Authorization = "Bearer secret-key"} -- Opcional
},
{
status = 200,
body = json.encode({result = "success", data = [1, 2, 3]}),
headers = {["Content-Type"] = "application/json"} -- Opcional
}
)

Parâmetros:

  • expected_request (tabela): A requisição esperada contendo method, url e opcionalmente headers e body
  • mock_response (tabela): A resposta simulada contendo status, body e opcionalmente headers

Dica importante: Você deve simular requisições HTTP antes de chamar o código que faz a requisição. As simulações são correspondidas exatamente, então certifique-se de que a URL, método e outros detalhes correspondam.

turn.test.assert_http_called(expected_request)

Verifica que uma chamada HTTP foi feita com os parâmetros especificados.

turn.test.assert_http_called({
method = "POST",
url = "https://api.example.com/webhook",
body = json.encode({event = "test", data = "value"})
})

Esta é uma asserção poderosa que falha se:

  • Nenhuma requisição HTTP foi feita
  • A requisição não corresponde aos parâmetros esperados (método, URL, corpo, etc.)

turn.test.get_http_requests()

Retorna uma tabela de todas as requisições HTTP feitas durante o teste. Útil para depuração ou verificações mais complexas.

local requests = turn.test.get_http_requests()
for i, req in ipairs(requests) do
print(string.format("Requisição %d: %s %s", i, req.method, req.url))
if req.body then
print("Corpo:", req.body)
end
end

-- Verificação personalizada
assert(#requests == 2, "Deveria ter feito exatamente 2 requisições HTTP")

Simulação de Chamadas entre Apps

turn.test.mock_app_call(app_name, event_name, mock_response)

Simula uma chamada para outro app. Útil ao testar integração entre apps sem precisar ter o outro app instalado.

turn.test.mock_app_call(
"payment_app", -- Nome do app
"process_payment", -- Nome do evento
{ -- Resposta simulada
success = true,
transaction_id = "txn_123",
amount = 100
}
)

turn.test.assert_app_called(app_name, event_name, expected_data)

Verifica que seu app chamou outro app com dados específicos.

turn.test.assert_app_called(
"payment_app",
"process_payment",
{
amount = 100,
currency = "USD",
customer_id = "cust_456"
}
)

turn.test.get_app_calls()

Retorna todas as chamadas de app feitas durante o teste.

local calls = turn.test.get_app_calls()
for i, call in ipairs(calls) do
print(string.format("Chamada de app %d: %s.%s", i, call.app, call.event))
print("Dados:", json.encode(call.data))
end

Gerenciamento de Contatos e Jornadas

turn.test.get_contact(contact_id)

Obtém um contato de teste. Após turn.test.reset(), dois contatos estão disponíveis: "contact-1" e "contact-2".

local contact = turn.test.get_contact("contact-1")
-- {id = "contact-1", phone = "+1234567890", name = "Test Contact 1"}

turn.test.create_contact(contact_data)

Cria um contato de teste personalizado.

local contact = turn.test.create_contact({
name = "John Doe",
phone = "+1234567890",
custom_field = "valor personalizado"
})

turn.test.get_journey(journey_id)

Obtém uma jornada de teste. Após turn.test.reset(), duas jornadas estão disponíveis: "journey-1" e "journey-2".

local journey = turn.test.get_journey("journey-1")

turn.test.create_journey(journey_data)

Cria uma jornada de teste personalizada.

local journey = turn.test.create_journey({
name = "test_journey",
description = "Jornada de Teste"
})

turn.test.add_message(contact, text, direction)

Adiciona uma mensagem de teste a um contato.

local contact = turn.test.get_contact("contact-1")
turn.test.add_message(contact, "Olá!", "inbound")
turn.test.add_message(contact, "Oi! Como posso ajudar?", "outbound")

turn.test.clear_contacts(), turn.test.clear_journeys(), turn.test.clear_messages()

Limpa dados de teste específicos sem redefinir tudo.

turn.test.clear_contacts()  -- Remove todos os contatos de teste
turn.test.clear_journeys() -- Remove todas as jornadas de teste
turn.test.clear_messages() -- Remove todas as mensagens de teste

Testes de Lease (Operações Assíncronas)

Ao testar operações assíncronas que usam turn.leases, você pode simular aquisição e liberação de leases.

turn.test.mock_lease_acquire(lease_name, callback)

Simula a aquisição de um lease e executa um callback.

it("deve processar lote de forma assíncrona", function()
turn.test.reset()

local lease_acquired = false
turn.test.mock_lease_acquire("process_batch", function(lease_id)
lease_acquired = true
return true -- Simula aquisição bem-sucedida
end)

app:on_event({}, number, "start_batch_process", {items = 100})

assert(lease_acquired == true, "Lease deveria ter sido adquirido")
end)

turn.test.assert_lease_released(lease_id)

Verifica que um lease foi liberado corretamente.

turn.test.assert_lease_released("lease_123")

Testes de Manifest

turn.test.load_manifest()

Carrega e analisa o arquivo manifest.json do seu app.

local manifest = turn.test.load_manifest()
assert(manifest.app.name == "my_app")
assert(manifest.app.version == "1.0.0")

turn.test.assert_manifest_has(field_path)

Verifica que o manifest tem um campo obrigatório.

turn.test.assert_manifest_has("app.name")
turn.test.assert_manifest_has("app.version")
turn.test.assert_manifest_has("app.description")

turn.test.validate_manifest()

Valida a estrutura completa do manifest.

local valid, errors = turn.test.validate_manifest()
assert(valid, "Validação do manifest falhou: " .. json.encode(errors))

Testes de Logger

turn.test.get_log_messages(level)

Recupera mensagens de log capturadas durante o teste, opcionalmente filtradas por nível de log. Útil para verificar se seu app registra mensagens apropriadas.

Parâmetros:

  • level (string, opcional): Filtrar por nível de log ("debug", "info", "warning", "error"). Se omitido, retorna todas as mensagens de log.

Retorna um array de entradas de log, cada uma contendo:

  • level (string): O nível do log
  • message (string): A mensagem de log
  • timestamp (number): Quando o log foi registrado
-- Obter todas as mensagens de log
local all_logs = turn.test.get_log_messages()

-- Obter apenas logs de erro
local errors = turn.test.get_log_messages("error")
for _, log in ipairs(errors) do
print(log.level .. ": " .. log.message)
end

-- Obter logs de aviso
local warnings = turn.test.get_log_messages("warning")
assert(#warnings == 0, "Esperado nenhum aviso")

turn.test.assert_logged(level, pattern)

Verifica se uma mensagem correspondente a um padrão Lua foi registrada no nível especificado. Retorna true se uma entrada de log correspondente foi encontrada, false caso contrário.

Parâmetros:

  • level (string): O nível de log a verificar ("debug", "info", "warning", "error")
  • pattern (string): Um padrão Lua para corresponder às mensagens de log
-- Verificar que mensagens específicas foram registradas
turn.logger.info("Processando pedido 12345")
turn.logger.error("Falha ao conectar à API de pagamento")

-- Verificar que mensagens foram registradas
assert(turn.test.assert_logged("info", "Processando pedido"))
assert(turn.test.assert_logged("error", "API de pagamento"))

-- Correspondência de padrões funciona com padrões Lua
assert(turn.test.assert_logged("info", "pedido %d+")) -- Corresponde a "pedido" seguido de dígitos

Exemplo: Testando Comportamento de Logging

describe("Processamento de pedido", function()
before(function()
turn.test.reset() -- Limpa logs capturados
end)

it("deve registrar etapas de processamento do pedido", function()
-- Processar um pedido (código do seu app)
App.on_event(app, number, "journey_event", {
function_name = "process_order",
args = {"ORD-123", 99.99}
})

-- Verificar que logging apropriado ocorreu
assert(turn.test.assert_logged("info", "Processando pedido ORD%-123"))
assert(turn.test.assert_logged("info", "Total do pedido: 99.99"))

-- Verificar que nenhum erro foi registrado
local errors = turn.test.get_log_messages("error")
assert(#errors == 0, "Esperado nenhum erro durante o processamento")
end)

it("deve registrar erros em entrada inválida", function()
App.on_event(app, number, "journey_event", {
function_name = "process_order",
args = {nil, -100}
})

-- Verificar que erro foi registrado
assert(turn.test.assert_logged("error", "Pedido inválido"))
end)
end)

Testes com Spy

turn.test.spy(func)

Cria um spy que envolve uma função e rastreia chamadas para fins de teste. Retorna uma tabela chamável que registra todas as invocações com seus argumentos. É compatível com Luerl e não requer módulos C ou a biblioteca debug.

Parâmetros:

  • func (função, opcional): A função para envolver. Se nil, cria um spy sem operação.

Retorna um objeto spy chamável com:

  • .calls (array): Lista de registros de chamadas, cada um com .vals (array de argumentos)
  • .call_count (número): Número total de vezes que o spy foi chamado
local turn = require("turn")

-- Criar um spy envolvendo uma função
local mock_client = {
get = turn.test.spy(function(self, resource_type, id)
return {
data = {
resourceType = resource_type,
id = id,
name = "Test Resource"
}
}
end)
}

-- Chamar a função espiada
local result = mock_client:get("Patient", "patient-123")

-- Verificar chamadas
assert(mock_client.get.call_count == 1, "Esperado que get seja chamado uma vez")
assert(#mock_client.get.calls == 1, "Esperado 1 registro de chamada")
assert(mock_client.get.calls[1].vals[2] == "Patient", "Esperado tipo de recurso Patient")
assert(mock_client.get.calls[1].vals[3] == "patient-123", "Esperado ID do paciente")

-- Verificar que o valor de retorno ainda funciona
assert(result.data.id == "patient-123", "Esperado que o spy retorne o resultado real")

Use spies para verificar chamadas de função em seus testes:

describe("Cliente de API", function()
local client

before(function()
turn.test.reset()

client = {
create = turn.test.spy(function(self, resource)
return { id = "new-123" }
end),
update = turn.test.spy(function(self, id, resource)
return { id = id, updated = true }
end)
}
end)

it("deve criar e atualizar recursos", function()
-- Executar operações
local created = client:create({ name = "Test" })
local updated = client:update("new-123", { name = "Updated" })

-- Verificar que create foi chamado
assert(client.create.call_count == 1, "Esperado que create seja chamado")
assert(client.create.calls[1].vals[2].name == "Test", "Esperado dados corretos")

-- Verificar que update foi chamado
assert(client.update.call_count == 1, "Esperado que update seja chamado")
assert(client.update.calls[1].vals[2] == "new-123", "Esperado ID correto")
end)
end)