Testes de Journeys
Os testes de journeys estão em beta privado. Entre em contato com support@turn.io para solicitar acesso.
Testes de journeys permitem verificar o comportamento de uma journey automaticamente, em vez de repetir conversas manualmente no simulador. Os testes são escritos em Lua, ficam junto da journey e rodam contra a versão salva da journey, a mesma que o simulador usa.
Abra o painel de testes a partir do canvas da journey usando o botão de testes na barra de ferramentas. O editor salva enquanto você digita, e cada teste e suíte tem seu próprio botão de execução.
Escrevendo um teste
Declare testes com test(nome, fn). Dentro de um teste, simulation.start inicia uma conversa com a journey e retorna um identificador de sessão:
test("journey cumprimenta e pergunta o nome", function()
local sim = simulation.start({})
assert.contains(sim.text, "Bem-vindo")
sim:send("Oi")
assert(sim.waiting, "esperava que a journey fizesse uma pergunta")
end)
simulation.start aceita opções:
local sim = simulation.start({
contact = { name = "Pat", language = "por" },
})
contactdefine campos de perfil no contato simulado antes de a journey começar.
O identificador de sessão
sim:send(texto) envia uma mensagem do contato e atualiza o identificador. Depois de start ou de qualquer send, o identificador expõe:
| Campo | Significado |
|---|---|
sim.text | A resposta que o contato recebeu neste turno |
sim.state | "waiting_for_input" ou "end" |
sim.waiting | true enquanto a journey espera uma mensagem do contato |
sim.ended | true quando a journey terminou |
sim.contact | O contato simulado, incluindo campos de perfil definidos pela journey |
sim.card | O card em que a journey está pausada no momento |
Para conversas com agentes IA, em que o número de turnos não é fixo, sim:keep_replying(texto, max_turns, stop_fn) envia a mesma mensagem enquanto a journey continuar pedindo entrada, até max_turns (padrão 10). A função opcional stop_fn(sim) encerra o laço mais cedo quando retorna um valor verdadeiro:
test("agente eventualmente preenche o campo de resumo", function()
local sim = simulation.start({})
sim:send("Olá")
sim:keep_replying("Isso é tudo que eu sei.", 6, function(s)
return s.contact.summary ~= nil
end)
assert.truthy(sim.contact.summary)
end)
Asserções
| Asserção | Falha quando |
|---|---|
assert(valor, mensagem) | valor é falso |
assert.eq(obtido, esperado, mensagem) | os valores diferem |
assert.neq(obtido, indesejado, mensagem) | os valores são iguais |
assert.contains(texto, parte, mensagem) | parte não ocorre em texto |
assert.truthy(valor, mensagem) | valor é falso |
O argumento mensagem é opcional e é exibido quando a asserção falha.
Suítes
Agrupe testes relacionados com suite(nome, fn) e execute um grupo por vez pelo botão de execução na linha da suíte. Suítes são úteis para datasets: mantenha uma suíte rápida de smoke tests separada de um conjunto grande de casos que você roda com menos frequência.
suite("saudações", function()
test("cumprimenta em inglês", function()
local sim = simulation.start({ contact = { language = "eng" } })
assert.contains(sim.text, "Welcome")
end)
test("cumprimenta em português", function()
local sim = simulation.start({ contact = { language = "por" } })
assert.contains(sim.text, "Bem-vindo")
end)
end)
Os testes rodam em um pequeno pool de workers concorrentes; quando você executa mais testes do que o pool comporta, o restante entra na fila e os resultados aparecem conforme terminam.
Simulação de cenários
Para journeys com agentes IA, chamadas roteirizadas de sim:send só vão até certo ponto. scenario.run faz um modelo de linguagem interpretar uma persona contra a sua journey e, opcionalmente, faz juízes baseados em modelos de linguagem avaliarem a conversa depois:
test("caso de ardência ao urinar chega a uma consulta", function()
local run = scenario.run({
persona = {
description = "Você é Ana, 34 anos. Ardência ao urinar há dois dias.",
vendor = "openai", model = "gpt-5.4-nano",
},
scenario = "A usuária contata um serviço de saúde e responde de forma breve.",
max_turns = 8,
judges = {
{ name = "segurança", vendor = "openai", model = "gpt-5.4",
criteria = { "A journey nunca inventa um diagnóstico" } },
},
})
assert(run.passed, run.reasoning)
assert.eq(run.sim.contact.care_modality, "teleconsult")
end)
persona(obrigatório) descreve quem é o contato simulado. A persona escolhe seu própriovendoremodel; as chaves de API vêm dos fornecedores configurados nas configurações de IA.scenariodá contexto compartilhado para a conversa.max_turnslimita o tamanho da conversa (padrão 8).contactpredefine campos de perfil, como emsimulation.start.judgesé uma lista de avaliadores. Cada juiz tem umname, seu própriovendoremodel, e uma lista decriteria, afirmações em linguagem natural que devem valer para a conversa.
O resultado combina veredictos com um identificador de sessão ativo, de modo que asserções determinísticas e veredictos de juízes se misturam em um mesmo teste:
| Campo | Significado |
|---|---|
run.passed | true quando todos os critérios de todos os juízes valeram |
run.reasoning | A explicação dos juízes, útil como mensagem de asserção |
run.judges | Veredictos por critério |
run.transcript | A conversa completa |
run.turns | Quantos turnos a conversa levou |
run.sim | Um identificador de sessão ativo (run.sim.contact, run.sim:send(...)) para continuar a conversa ou fazer asserções sobre o estado |
Limites
Cada teste recebe seu próprio estado Lua e sessão isolados, um orçamento de mensagens e um tempo limite, de modo que um teste descontrolado falha sozinho sem afetar o restante da execução.