Como automatizar testes de regressão no servidor de MU Online
Crie uma suíte de testes de regressão automatizados para validar que atualizações de configuração, eventos e itens do seu servidor de MU Online não quebram funcionalidades que já funcionavam antes.
Cada atualização em um servidor de MU Online — uma nova season, um evento customizado, um ajuste de taxa de drop, uma correção de bug — carrega o risco de quebrar algo que já funcionava. É extremamente comum ver um servidor lançar uma correção pontual e, sem perceber, derrubar a Chaos Machine ou imp
Cada atualização em um servidor de MU Online — uma nova season, um evento customizado, um ajuste de taxa de drop, uma correção de bug — carrega o risco de quebrar algo que já funcionava. É extremamente comum ver um servidor lançar uma correção pontual e, sem perceber, derrubar a Chaos Machine ou impedir login em uma classe específica, só descobrindo o problema pelos jogadores reclamando no Discord. Este tutorial mostra como montar uma suíte de testes de regressão automatizados que roda antes de qualquer atualização ir para produção, cobrindo os fluxos mais críticos do servidor: login, criação de personagem, drop, Chaos Machine e eventos.
Por que testes de regressão importam tanto em servidores privados
Diferente de um software comum, um servidor de MU Online tem uma característica particular: as "regras de negócio" vivem espalhadas entre arquivos de configuração (.txt, .xml, .ini), scripts de evento, banco de dados e o próprio binário do emulador. Uma mudança pequena em um arquivo de configuração pode ter efeito colateral em um sistema aparentemente não relacionado — por exemplo, alterar a taxa de drop de um monstro pode, por erro de digitação, zerar o drop de outro item na mesma linha. Testes de regressão automatizados existem justamente para pegar esse tipo de efeito colateral antes que chegue aos jogadores.
Definindo o escopo mínimo viável da suíte
Não é necessário (nem realista) testar tudo desde o início. Priorize pelos fluxos que, se quebrarem, geram o maior volume de reclamações e maior dano à reputação do servidor:
| Fluxo crítico | Por que priorizar | Frequência de regressão |
|---|---|---|
| Login e criação de personagem | Bloqueia 100% dos jogadores se quebrar | Alta (qualquer mudança de conta/char) |
| Drop básico de itens | Afeta a economia inteira do servidor | Média-alta (mudanças de configuração de monstro) |
| Chaos Machine (criação/combinação) | Item mais usado no endgame | Média (mudanças em receitas) |
| Entrada em eventos (BC, DS, CC) | Afeta engajamento diário | Média (mudanças de script de evento) |
| Sistema de sockets/Seed Spheres | Afeta itens de topo de progressão | Baixa, mas crítica quando ocorre |
| Loja/cash shop | Afeta receita direta | Alta (qualquer mudança de preço/item) |
Arquitetura da suíte de testes
O desenho recomendado separa os testes em camadas, do mais rápido/barato ao mais lento/caro, para rodar os baratos com frequência e os caros apenas antes de releases:
| Camada | O que valida | Custo de execução |
|---|---|---|
| Testes de configuração | Sintaxe e consistência dos arquivos .txt/.xml | Segundos |
| Testes de banco de dados | Integridade de schema e dados de referência | Segundos a minutos |
| Testes de protocolo/GM command | Fluxos via comandos administrativos (sem cliente gráfico) | Minutos |
| Testes end-to-end (cliente real/bot) | Fluxo completo como o jogador vive | Minutos a dezenas de minutos |
Testes de configuração (validação de sintaxe e consistência)
A camada mais barata e mais valiosa: um script que valida se os arquivos de configuração ainda têm o número de colunas esperado e se valores críticos não ficaram fora de faixa, antes mesmo de subir o servidor:
import csv
def validar_item_txt(caminho, colunas_esperadas=25):
erros = []
with open(caminho, encoding='latin-1') as f:
for i, linha in enumerate(f, 1):
if linha.strip().startswith('//') or not linha.strip():
continue
campos = linha.split('\t')
if len(campos) != colunas_esperadas:
erros.append(f"Linha {i}: {len(campos)} colunas, esperado {colunas_esperadas}")
return erros
erros = validar_item_txt("Data/Item/Item.txt")
if erros:
print(f"FALHA: {len(erros)} inconsistências encontradas")
for e in erros[:10]:
print(e)
else:
print("OK: Item.txt consistente")
Testes de banco de dados (schema e dados de referência)
Depois de uma migração ou atualização de emulador, é comum uma tabela perder uma coluna ou um valor de referência mudar sem ninguém notar. Um teste simples de schema:
-- Verifica se colunas críticas ainda existem após uma migração
SELECT COUNT(*) AS colunas_encontradas
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Character'
AND COLUMN_NAME IN ('Strength', 'Dexterity', 'Vitality', 'Energy', 'Level');
-- Esperado: 5
-- Verifica se os dados de referência de classe/mapa não foram corrompidos
SELECT COUNT(*) FROM MapInfo WHERE MapNumber BETWEEN 0 AND 10;
-- Esperado: um número conhecido e estável
Testes via GM command (sem precisar do cliente gráfico)
Muitos emuladores expõem comandos administrativos via console do servidor ou via chat de GM que permitem testar fluxos sem abrir o cliente completo — útil para automação em CI:
# Pseudocódigo de teste via comando de GM (adaptar ao protocolo real do emulador)
def testar_criacao_item(conexao_gm, tipo, indice, nivel):
resposta = conexao_gm.enviar_comando(f"/make {tipo} {indice} {nivel}")
assert "criado" in resposta.lower(), f"Falha ao criar item {tipo}:{indice} — resposta: {resposta}"
def testar_drop_monstro(conexao_gm, monstro_id):
resposta = conexao_gm.enviar_comando(f"/killmob {monstro_id}")
# Valida no log/banco se algum drop foi gerado
Testes end-to-end com bot simulando o jogador
Para os fluxos mais críticos (login, criação de personagem, entrada em evento), vale ter um bot que efetivamente conecta e joga um roteiro fixo, validando o resultado esperado em cada etapa:
def teste_login_e_criacao_char(conta_teste, senha_teste):
cliente = ClienteMuTeste(host="staging.meuservidor.com", porta=44405)
assert cliente.login(conta_teste, senha_teste), "Login falhou"
assert cliente.criar_personagem("TesteQA01", classe="DarkKnight"), "Criação de personagem falhou"
assert cliente.entrar_no_jogo(), "Falha ao entrar no mundo com o personagem criado"
cliente.desconectar()
Mantenha uma conta de teste dedicada (qa_bot_01) separada de contas reais, resetada a cada execução para não acumular estado entre testes.
Testando o fluxo da Chaos Machine
Como a Chaos Machine é um dos fluxos mais sensíveis a mudanças de configuração (receitas, taxa de sucesso), vale um teste dedicado que gera os itens de entrada via GM, tenta a combinação e valida o resultado:
def teste_chaos_machine(conexao_gm, receita_id, itens_entrada):
for item in itens_entrada:
conexao_gm.enviar_comando(f"/make {item['tipo']} {item['indice']} {item['nivel']}")
resultado = conexao_gm.enviar_comando(f"/testarcombinacao {receita_id}")
assert resultado in ("sucesso", "falha_esperada"), f"Resultado inesperado: {resultado}"
Testando entrada em eventos automaticamente
Reaproveitando a lógica de leitura de estado de evento (já usada no pipeline de anúncio automático), é possível validar que o NPC de entrada do evento realmente move o personagem de teste para o mapa correto:
def teste_entrada_devil_square(cliente_teste):
cliente_teste.falar_com_npc("Devil Messenger")
cliente_teste.selecionar_opcao("Entrar no Devil Square")
mapa_atual = cliente_teste.obter_mapa_atual()
assert mapa_atual == "Devias 2 (Evento)", f"Esperado Devias 2, obtido {mapa_atual}"
Integrando a suíte a um pipeline de CI
O maior ganho vem de rodar a suíte automaticamente sempre que uma configuração é alterada em staging, antes de promover para produção. Um pipeline simples baseado em script, sem depender de infraestrutura complexa de CI:
#!/bin/bash
set -e
echo "1. Validando arquivos de configuração..."
python3 testes/validar_configs.py
echo "2. Validando schema do banco..."
mysql -u teste -p"$DB_PASS" mu_staging < testes/validar_schema.sql
echo "3. Rodando testes via GM command..."
python3 testes/testes_gm.py
echo "4. Rodando testes end-to-end..."
python3 testes/testes_e2e.py
echo "Suíte de regressão concluída com sucesso. Liberado para produção."
Se qualquer etapa falhar (set -e interrompe o script no primeiro erro), a promoção para produção deve ser bloqueada manualmente até a causa ser corrigida.
Mantendo um changelog de regressões encontradas
Toda falha pega pela suíte (ou, pior, escapada dela) deve ser documentada: o que quebrou, por que, e o que foi corrigido. Isso evita que o mesmo bug reapareça silenciosamente em uma atualização futura, e ajuda a priorizar quais novos testes adicionar à suíte:
| Data | Mudança que causou | Sintoma | Correção | Teste adicionado depois |
|---|---|---|---|---|
| 2026-06-10 | Ajuste de drop de monstro | Item X parou de dropar | Corrigido índice na linha errada | Teste de drop por monstro |
| 2026-07-02 | Atualização de emulador | Chaos Machine travava | Receita desatualizada no config novo | Teste de combinação automatizado |
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Suíte não pega a regressão real | Escopo de testes limitado aos fluxos errados | Priorize os fluxos de maior impacto (login, drop, Chaos Machine) |
| Testes end-to-end são muito lentos | Suíte roda tudo a cada pequena mudança | Separe camadas rápidas (config/schema) das lentas (e2e), rode e2e só antes de release |
| Conta de teste acumula itens/estado entre execuções | Falta de reset/limpeza pós-teste | Recrie/limpe a conta de teste no início de cada execução |
| Testes passam em staging mas quebra em produção | Ambientes com configuração divergente | Sincronize configs entre staging e produção antes de cada teste |
| Ninguém revisa as falhas da suíte | Ausência de processo/responsável definido | Defina um dono da suíte e trate falha como bloqueador de release |
| Regressão do mesmo tipo se repete | Falha não documentada, teste não adicionado depois | Mantenha o changelog de regressões e adicione teste específico após cada uma |
Checklist de testes de regressão
- Escopo mínimo de fluxos críticos definido e priorizado.
- Testes de configuração (sintaxe/consistência) implementados.
- Testes de schema/dados de referência do banco implementados.
- Testes via GM command cobrindo criação de item e drop.
- Teste end-to-end de login e criação de personagem funcionando.
- Teste da Chaos Machine e de entrada em eventos automatizado.
- Pipeline de execução (script/CI) rodando antes de cada promoção para produção.
- Changelog de regressões encontradas mantido e revisado.
Com a suíte de regressão rodando antes de cada atualização, você troca o "torcer para não ter quebrado nada" por confirmação real antes de expor a mudança aos jogadores. Se o seu servidor ainda não tem um ambiente de staging separado da produção, esse é o próximo passo natural — revise o tutorial de criação de servidor de MU Online para estruturar essa separação corretamente.
Perguntas frequentes
O que é exatamente um teste de regressão nesse contexto?
É um teste que confirma que uma funcionalidade que já funcionava (login, drop de item, criação na Chaos Machine, entrada em evento) continua funcionando depois de uma mudança de configuração, atualização de emulador ou correção de bug. O objetivo é pegar quebras não intencionais antes dos jogadores.
Preciso escrever testes para tudo desde o primeiro dia?
Não. Comece cobrindo os fluxos mais críticos e mais frequentemente quebrados por mudanças: login, criação de personagem, drop básico, Chaos Machine e entrada em eventos. Expanda a suíte conforme identificar bugs recorrentes que poderiam ter sido pegos por um teste.
Dá para testar sem um cliente de MU completo?
Sim, para a maior parte dos testes de servidor (login, criação de item via GM command, consulta de banco) é possível emular o protocolo diretamente ou usar comandos administrativos, sem abrir o cliente gráfico. Testes de UI/cliente exigem uma abordagem separada (bot com cliente real ou emulador de input).
Com que frequência devo rodar a suíte de regressão?
Idealmente, toda vez que uma configuração, script de evento ou atualização de emulador for alterada em staging, antes de promover para produção. Também é saudável rodar a suíte completa diariamente em staging, mesmo sem mudanças, para pegar regressões causadas por fatores externos (ex.: expiração de dados de teste).
O que fazer quando um teste falha?
Trate como bloqueador: não promova a mudança para produção até entender e corrigir a causa raiz. Documente a falha, a causa e a correção em um changelog interno — isso evita que o mesmo bug reapareça em uma futura atualização sem que ninguém lembre que já foi corrigido antes.