☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

Mostrar mensagens com a etiqueta QA. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta QA. Mostrar todas as mensagens

quinta-feira, 15 de fevereiro de 2024

O Mestre Persa Algoritm Entra no CPD — A Noite em que COBOL Descobriu que “Funcionou Aqui” Não Era Plano de Testes

 

Bellacosa Mainframe testando software

☕ Um Café no Bellacosa Mainframe

O Mestre Persa Algoritm Entra no CPD — A Noite em que COBOL Descobriu que “Funcionou Aqui” Não Era Plano de Testes

Ou: como Black Box, White Box, Regression, Selenium, APIs, CI/CD, Db2, CICS, MQ, performance, bugs, usuários furiosos e um velho sábio persa ensinaram a um programador COBOL que qualidade não é provar que o sistema funciona — é descobrir todas as maneiras pelas quais ele pode falhar antes das três da manhã

Há uma velha história, provavelmente inventada por algum operador de mainframe durante um plantão de madrugada, sobre um mestre persa chamado Algoritm.

Alguns dizem que ele veio de Bagdá.

Outros juram que apareceu pela primeira vez em Samarcanda carregando pergaminhos cheios de fórmulas.

Um analista mais desconfiado afirmou que seu verdadeiro nome deveria ser alguma corruptela de Al-Khwarizmi, mas ninguém teve coragem de abrir uma change request para corrigir o cadastro.

O fato é que, numa noite qualquer, o Mestre Persa Algoritm atravessou a porta do CPD.

Olhou para os racks.

Observou as luzes piscando.

Passou pela console do z/OS.

Viu um programador COBOL iniciante comemorando diante da tela.

— Funcionou!

Algoritm parou.

— O que funcionou?

— Meu programa.

— Quantas vezes?

— Uma.

O persa acariciou a barba.

— Então você não sabe se funciona.

— Como assim?

— Você sabe apenas que não falhou daquela maneira específica, naquele instante específico, usando aqueles dados específicos.

O programador ficou em silêncio.

Algoritm puxou uma cadeira.

— Prepare o café. Esta noite falaremos sobre testes.

E é aqui que começa nossa viagem.



1. Testar software não é procurar botão quebrado

Quando alguém está começando em programação, especialmente vindo de uma mentalidade muito orientada ao código, é fácil imaginar teste assim:

executei
↓
não deu abend
↓
está certo

No mainframe existe até uma versão clássica:

JOB ENDED - MAXCC=0000

E imediatamente surge a tentação:

“Pronto. Funcionou.”

Não necessariamente.

MAXCC=0000 significa que aquele job terminou sem retornar uma condição de erro significativa naquele processamento.

Não significa:

dados corretos
regras corretas
performance correta
segurança correta
concorrência correta
integração correta

Pode existir um sistema absolutamente errado terminando com RC=0.

Essa é uma das primeiras lições do Mestre Algoritm:

Software Testing é uma investigação sobre comportamento e risco.

O teste tenta responder:

O que deveria acontecer?
        ↓
O que aconteceu?
        ↓
Existe diferença?
        ↓
Por quê?
        ↓
Qual o impacto?

Portanto, o objetivo do teste não é somente encontrar bugs.

Ele também serve para:

  • aumentar confiança no sistema;

  • reduzir risco;

  • verificar requisitos;

  • ajudar decisões de release;

  • encontrar comportamentos inesperados;

  • descobrir problemas antes que o cliente descubra.

Porque existe algo pior do que um tester descobrir um bug.

É o cliente descobrir.



2. O primeiro paradoxo: testes nunca provam ausência de bugs

Algoritm pega uma xícara.

— Quantos testes você precisa executar para provar que seu programa não possui erros?

O programador pensa.

— Mil?

— Não.

— Um milhão?

— Não.

— Todos?

Algoritm sorri.

— Agora começou a entender.

Um dos princípios fundamentais dos testes diz:

Testing shows the presence of defects, not their absence.

Ou seja:

se encontramos erro, sabemos que existe erro.

Se não encontramos, apenas não encontramos ainda.

Essa distinção parece filosófica, mas é profundamente prática.

Imagine:

IF WS-SALDO >= WS-SAQUE
    SUBTRACT WS-SAQUE FROM WS-SALDO
ELSE
    MOVE 'SALDO INSUFICIENTE'
      TO WS-MENSAGEM
END-IF

Testamos:

saldo = 1000
saque = 100

Resultado perfeito.

Mas faltam:

saldo = 100
saque = 100

saldo = 99
saque = 100

saque = 0

saque negativo

saque enorme

saldo inválido

conta bloqueada

duas requisições simultâneas

Aquele primeiro teste apenas mostrou que:

1000 - 100 = 900

Não mostrou que o sistema bancário está pronto para produção.



3. Teste exaustivo é impossível

Agora Algoritm desenha numa folha:

LOGIN

Temos usuário e senha.

Parece simples.

Mas considere:

usuário correto
usuário errado
senha correta
senha errada
conta bloqueada
conta expirada
senha expirada
campo vazio
espaço
Unicode
caracteres especiais
string gigantesca
tentativas repetidas
sessão existente
rede instável
banco indisponível

E cada uma dessas condições pode combinar-se com outras.

A explosão combinatória acontece rapidamente.

Portanto:

Exhaustive testing is impossible.

É impossível testar cada combinação possível de entrada, estado, ambiente e sequência.

Por isso precisamos de inteligência.

Não testamos tudo.

Testamos aquilo que oferece melhor cobertura de risco.

Esse é o momento em que testes deixam de parecer uma checklist e começam a parecer engenharia.


4. SDLC e STLC — construir e testar não deveriam viver separados

A abordagem tradicional do desenvolvimento frequentemente parecia uma procissão burocrática:

Analista
  ↓
Desenvolvedor
  ↓
Tester
  ↓
Produção

O tester recebia o sistema praticamente pronto.

Encontrava 47 problemas.

O desenvolvedor dizia:

“Mas agora vai atrasar o projeto!”

O tester respondia:

“Eu não criei os 47 bugs.”

E começava uma guerra civil.

O SDLC — Software Development Life Cycle cobre o ciclo do software:

requisitos
↓
análise
↓
design
↓
desenvolvimento
↓
testes
↓
deploy
↓
manutenção

Já o STLC — Software Testing Life Cycle trata especificamente das atividades de teste:

análise de requisitos
↓
planejamento
↓
desenho dos testes
↓
preparação do ambiente
↓
execução
↓
encerramento

Mas numa organização madura esses ciclos se cruzam.

Testing não deveria começar quando a programação termina.

O tester precisa participar antes.

Isso é o famoso Shift Left.


5. Shift Left — encontrar bugs antes que eles virem código

Algoritm pergunta:

— Qual é o bug mais barato?

O programador responde:

— O que é rápido de corrigir?

— Não. O que ainda não virou código.

Considere um requisito:

“O cliente poderá transferir valores entre contas.”

Parece perfeito.

Até alguém perguntar:

qual limite?
pode enviar para a própria conta?
conta bloqueada pode transferir?
o que ocorre no limite exato?
o que ocorre se o débito acontecer e o crédito falhar?
como evitar transferência duplicada?
há timeout?

Essas perguntas podem revelar problemas ainda durante os requisitos.

Nenhuma linha COBOL foi compilada.

Nenhum JCL foi submetido.

Nenhum DBA foi acordado.

Esse é um dos maiores ganhos de testes modernos:

testar ideias antes de testar programas.


6. Os níveis de teste — do parafuso ao avião inteiro

O material apresenta níveis clássicos:

Unit
↓
Integration
↓
System
↓
Acceptance

Podemos pensar numa fábrica de aviões.

Você testa:

parafuso
motor
asa
avião completo
voo

Não basta verificar o parafuso.

Também não faz sentido esperar o avião completo para descobrir que o parafuso estava errado.


7. Unit Testing — teste perto do código

Unit Test testa uma pequena unidade isoladamente.

Imagine:

COMPUTE WS-JUROS =
    WS-SALDO * WS-TAXA

Queremos testar:

saldo positivo
saldo zero
saldo negativo
taxa zero
decimais
arredondamento
overflow

Unit Tests são normalmente:

rápidos
repetíveis
isolados
baratos

Eles ajudam a encontrar o problema perto de onde ele nasceu.

No ecossistema COBOL moderno há inclusive ferramentas e frameworks voltados a unit testing, e isso destrói a velha lenda:

“COBOL não combina com testes modernos.”

Combina perfeitamente.

O código não sabe que nasceu em 1959.


8. Integration Testing — o sistema quebra quando começa a conversar

Aqui temos um fenômeno clássico.

Todos os módulos funcionam.

Juntos, não.

Imagine:

Aplicativo
 ↓
API Gateway
 ↓
z/OS Connect
 ↓
CICS
 ↓
COBOL
 ↓
Db2

Separadamente:

API OK
CICS OK
COBOL OK
Db2 OK

Mas integração pode falhar porque:

JSON ≠ copybook
UTF-8 ≠ EBCDIC
decimal ≠ COMP-3
timestamp ≠ formato esperado
campo obrigatório desapareceu

Integration Testing verifica os contratos entre os componentes.

É aí que aparecem erros que ninguém tinha quando estava sozinho.

Quase como reunião de família.


9. System Testing — teste aquilo que o usuário realmente percebe

O usuário não pensa:

“Estou invocando um microsserviço de estoque.”

Ele pensa:

“Estou comprando um notebook.”

Logo, System Testing examina o fluxo completo.

login
↓
busca
↓
produto
↓
carrinho
↓
checkout
↓
pagamento
↓
estoque
↓
pedido
↓
confirmação

Pode haver vinte componentes internos.

Para o cliente existe apenas uma pergunta:

“Minha compra funcionou?”

Essa diferença é essencial.


10. Functional Testing versus Non-Functional Testing

Aqui está uma das divisões mais elegantes.

Functional Testing pergunta:

O que o sistema faz?

Non-Functional Testing pergunta:

Quão bem ele faz?

Imagine transferência bancária.

Funcionalmente:

debita origem
credita destino
gera comprovante

Perfeito.

Mas leva 45 segundos.

Tecnicamente funciona.

Praticamente é um desastre.

Ou funciona rapidamente, mas:

qualquer cliente consulta a conta de outro cliente

Funcionalmente responde.

Em segurança, falhou monstruosamente.

Por isso software de qualidade precisa dos dois lados.


11. Black Box Testing — teste o sistema sem olhar dentro

Black Box é como testar uma máquina fechada.

Você conhece:

entrada
resultado esperado

Não precisa saber como o programa foi implementado.

Exemplo:

idade aceita: 18 até 65

Não testamos todos os números do universo.

Usamos técnicas.


12. Equivalence Partitioning — dividir o universo

Podemos criar partições:

idade < 18      inválida
18–65           válida
idade > 65      inválida

Selecionamos representantes:

17
30
66

Isso reduz bastante o número de testes mantendo boa cobertura.

Mestre Algoritm comenta:

— Um bom tester não testa muito. Testa inteligentemente.


13. Boundary Value Analysis — o perigo mora na fronteira

Programadores são criaturas especialmente vulneráveis aos limites.

Se a regra é:

1 até 100

testes interessantes:

0
1
2
99
100
101

Porque bugs surgem em diferenças como:

<
<=
>
>=

Em COBOL pense imediatamente em:

PIC
OCCURS
subscripts
COMP-3
tamanho de registro
campo numérico

A fronteira é um habitat natural de bugs.


14. Decision Table — excelente para regra de negócio

Imagine autorização de crédito:

cliente ativo?
saldo suficiente?
limite disponível?
conta regular?

Cada condição possui combinações.

Uma Decision Table deixa explícito:

AtivoSaldoLimiteResultado
SimSimSimAprova
NãoSimSimRejeita
SimNãoSimRejeita
SimSimNãoRejeita

É particularmente valiosa em sistemas financeiros cheios de regras condicionais.

E sistemas COBOL adoram regras condicionais.

Às vezes até demais.


15. State Transition Testing — o passado importa

Alguns comportamentos dependem do estado.

Considere login:

ACTIVE
 ↓ erro
ACTIVE
 ↓ erro
ACTIVE
 ↓ erro
LOCKED

O terceiro erro produz algo diferente do primeiro.

Portanto:

estado atual
+
evento
=
novo estado

Isso aparece em:

login
pagamentos
pedidos
CICS
workflow
mensageria

Testing de estado verifica justamente essas transições.


16. White Box Testing — agora abrimos o programa

No White Box conhecemos a estrutura interna.

Imagine:

IF A > B
    PERFORM ROTINA-A
ELSE
    PERFORM ROTINA-B
END-IF

Precisamos exercitar:

True
False

E podemos medir:

Statement Coverage
Branch Coverage
Condition Coverage
Path Coverage
Loop Coverage

Mas atenção ao Easter Egg escondido no templo persa:

100% coverage não significa 100% correto.

Podemos executar todas as linhas de um programa errado.

Coverage mede execução.

Não mede sabedoria.


17. Regression versus Retesting — duas perguntas diferentes

Bug:

senha contendo @ falha

Corrigimos.

Retesting

Pergunta:

A correção funcionou?

Testamos novamente a senha.

Regression

Pergunta:

A correção quebrou outra coisa?

Testamos:

login
logout
reset password
MFA
sessão
bloqueio

Resumo Bellacosa:

RETEST:
"Consertou o vazamento?"

REGRESSION:
"Consertando o vazamento, estourou o encanamento da cozinha?"

Essa é a diferença.


18. Defect Life Cycle — o bug também tem carreira

Um bug costuma viajar:

New
 ↓
Assigned
 ↓
Open
 ↓
In Progress
 ↓
Fixed
 ↓
Retest
 ↓
Verified
 ↓
Closed

Mas no mundo real encontramos parentes:

Reopened
Rejected
Duplicate
Deferred
Cannot Reproduce
Won't Fix
Blocked

O mais famoso é:

Cannot Reproduce.

O tester jura que aconteceu.

O developer jura que não.

Produção entra na reunião e diz:

Aconteceu comigo também.

Silêncio.

Um bom bug report precisa conter:

versão
ambiente
pré-condições
passos
dados
resultado esperado
resultado observado
timestamp
logs
evidências

“Não funciona” não é bug report.

É pedido de ajuda.


19. Severity e Priority — gravidade não é urgência

Severity:

Quanto dói?

Priority:

Quão rápido precisamos tratar?

Imagine erro ortográfico na tela principal durante uma demonstração internacional.

Severity:

Low

Priority:

P1

Agora imagine crash crítico numa função administrativa usada uma vez ao ano.

Severity:

Critical

Priority pode não ser P1.

Portanto:

SEVERITY != PRIORITY

Severity está relacionada ao impacto do defeito.

Priority envolve necessidade de negócio.


20. Manual Testing — humanos ainda são surpreendentemente úteis

Chegamos a uma moda perigosa:

“IA e automação vão eliminar teste manual.”

Não.

Teste manual é particularmente útil em:

exploratory testing
usability
interface
novas features
comportamentos inesperados
investigação

O ser humano percebe coisas que um script não foi instruído a perceber.

Um script pode validar:

botão existe

Um humano percebe:

“Ninguém vai entender para que serve esse botão.”

São problemas diferentes.


21. Test Automation — automatize repetição, não pensamento

Automação faz sentido quando testes são:

repetitivos
estáveis
frequentes
determinísticos
caros manualmente

Regression Testing é candidato clássico.

Mas automatizar tudo gera outra doença:

10.000 scripts
+
interface alterada
=
10.000 problemas de manutenção

Automação tem ROI.

Existe:

custo inicial
infraestrutura
manutenção
dados
execução
investigação

Por isso:

Automatize o teste certo, não simplesmente tudo que possui botão.


22. A pirâmide dos testes

A pirâmide clássica:

        UI
       /--\
      API
     /----\
    UNIT
   /______\

A base contém muitos Unit Tests.

Depois APIs e integração.

No topo poucos E2E/UI.

Por quê?

Unit Tests são rápidos.

UI Tests são relativamente lentos e frágeis.

Se toda regra de negócio for validada por Selenium abrindo browser, clicando em menus e esperando telas, prepare café.

Muito café.


23. Selenium — o mensageiro do navegador

Selenium automatiza navegadores.

Fluxo:

test script
 ↓
WebDriver
 ↓
browser
 ↓
application

Podemos:

abrir URL
localizar elementos
clicar
preencher
capturar texto
validar resultado

O Selenium é poderoso.

Mas não deve testar tudo.

Se uma regra pode ser verificada diretamente na API, normalmente o teste será:

mais rápido
mais estável
mais simples

24. O clássico sleep(5) — a oração do programador cansado

Considere:

Thread.sleep(5000);

Tradução:

“Ó sistema, por favor tenha terminado dentro de cinco segundos.”

Se termina em 100 ms:

perdemos tempo.

Se termina em 5,01 segundos:

falha.

Melhor é esperar uma condição:

botão clicável
elemento visível
resposta concluída

Esses são os Explicit Waits.

Eles ajudam a reduzir testes flakey.

Flaky Test é aquele teste adorável que:

passa
falha
passa
falha

sem mudança no programa.

O Mestre Algoritm certamente jogaria esse teste no deserto.


25. API Testing — HTTP 200 não é certificado de perfeição

API Testing verifica:

endpoint
method
headers
authentication
request
response
schema
status
performance
security

Imagine:

POST /transfer

Recebemos:

HTTP 200

Excelente?

Talvez.

Precisamos verificar:

o dinheiro saiu?
chegou?
duplicou?
foi persistido?
auditado?

Uma resposta HTTP tecnicamente válida pode carregar comportamento de negócio errado.

Esse é um conceito extremamente importante.


26. Performance Testing — o sistema pode funcionar e ainda assim morrer

Performance Testing não significa apenas medir velocidade.

Temos:

Load Testing

Carga esperada.

Stress Testing

Carga além do esperado.

Spike Testing

Aumento repentino.

Soak Testing

Carga prolongada.

Volume Testing

Grandes volumes de dados.

Scalability Testing

Capacidade de crescer.

Uma aplicação pode sobreviver cinco minutos perfeitamente.

Depois de seis horas:

memory leak
pool esgotado
fila crescente
storage acabando

O Soak Test revela esses monstros.


27. Métricas — média é uma mentirosa educada

Imagine:

Average Response Time = 200 ms

Fantástico.

Mas:

P50 = 100 ms
P95 = 2 s
P99 = 12 s

A maioria está feliz.

Uma parcela está sofrendo profundamente.

Por isso usamos percentis.

Também observamos:

TPS
throughput
latency
error rate
CPU
memory
disk
network

Uma métrica isolada conta metade da história.


28. Agile Testing — testing deixa de ser departamento

Agile Testing traz uma mudança fundamental:

qualidade é responsabilidade do time.

Não:

DEV fez
↓
QA testa

Mas:

PO
↕
Developer
↕
Tester
↕
Operations

Testing acontece continuamente.

O QA deixa de ser “polícia do bug”.

Torna-se parceiro da engenharia.


29. CI/CD — a esteira que não aceita promessa

No CI/CD:

commit
↓
build
↓
unit test
↓
static analysis
↓
integration
↓
API test
↓
security
↓
deploy
↓
monitor

Se um quality gate falha:

STOP

No mainframe isso pode envolver:

Git
↓
DBB
↓
COBOL Compile
↓
Link Edit
↓
Unit Tests
↓
Integration
↓
Deploy

Sim.

COBOL pode viver dentro de pipeline moderno.

Ele não precisa continuar esperando fita magnética e formulário de mudança datilografado.


30. “Works in DEV, fails in PROD”

Existe uma inscrição secreta na parede de todo datacenter:

Funciona no meu ambiente.

Em produção encontramos diferenças:

configuração
dados
versões
RACF
certificados
network
Db2
CICS
feature flags
capacity

Código igual não garante ambiente igual.

Portanto:

ambiente também faz parte do sistema.

Essa ideia é frequentemente esquecida.


31. O cenário assustador: usuário vendo dados de outro usuário

Imagine:

Cliente A
 ↓
consulta conta
 ↓
dados do Cliente B

O sistema pode responder:

HTTP 200
tempo = 70 ms
JSON válido

Performance maravilhosa.

Funcionalidade respondendo.

Segurança devastada.

Aqui entram:

authentication
authorization
session
access control
data isolation

Essa é a prova definitiva de que qualidade é multidimensional.


32. “Dados às vezes não são salvos”

Algoritm fica sério.

— Qual palavra mais perigosa num bug report?

O programador responde:

— Abend?

— Não.

— Corrupção?

— Não.

— Qual?

Às vezes.

“Às vezes não salva.”

Pode indicar:

race condition
lock
timeout
rollback
commit
deadlock
concorrência
network failure

Problemas intermitentes são particularmente difíceis porque dependem de timing e estado.

Exemplo:

DEBIT
↓
serviço externo
↓
timeout
↓
CREDIT?

Esse tipo de teste começa a entrar em resiliência.


33. Observabilidade — a página que deveria existir

Eu acrescentaria ao material:

Testing + Observability

Não basta saber:

FAILED

Precisamos saber:

WHY?

Logs.

Metrics.

Traces.

No mainframe:

SQLCODE
CICS RESP
MQ Reason Code
SMF
return codes
Abend codes

Em sistemas distribuídos, um correlation ID permite acompanhar:

Mobile
↓
API
↓
z/OS Connect
↓
CICS
↓
COBOL
↓
Db2

Sem observabilidade, debugging moderno vira arqueologia.


34. Resilience Testing — provoque o desastre antes que o desastre aconteça

Outra evolução interessante:

E se Db2 cair?
E se MQ parar?
E se a rede ficar lenta?
E se o serviço externo devolver lixo?
E se o certificado expirar?

Resilience Testing não pergunta apenas:

o sistema quebra?

Pergunta:

como o sistema quebra?

Existe enorme diferença entre:

mensagem de indisponibilidade

e:

dados financeiros inconsistentes

Sistemas críticos precisam falhar com segurança.


35. E finalmente: como pensa um tester de verdade?

Voltamos ao Mestre Algoritm.

O iniciante pergunta:

— Mestre, então qual é a principal ferramenta de um tester?

Algoritm aponta para a cabeça.

Não Selenium.

Não Postman.

Não JMeter.

Não Jenkins.

Não alguma ferramenta de IA.

A principal ferramenta é:

curiosidade estruturada.

O desenvolvedor pergunta:

Como faço isso funcionar?

O tester pergunta:

Como faço isso falhar?

O engenheiro de qualidade pergunta:

Qual falha importa mais?

O engenheiro de resiliência pergunta:

Quando isso inevitavelmente falhar,
como impedimos que o desastre se espalhe?

Isso representa uma progressão extremamente interessante:

JÚNIOR
"Funciona?"

↓


PLENO
"Quando falha?"

↓


SÊNIOR
"Onde pode falhar?"

↓


TEST ENGINEER
"Como mensuramos o risco?"

↓


QUALITY ENGINEER
"Como prevenimos e detectamos?"

↓


SRE / RESILIENCE
"Como sobrevivemos à falha?"

☕ Epílogo — o Mestre Persa desliga o terminal

O relógio marcava 03:17.

O café havia acabado.

O programador COBOL olhou novamente para seu job.

Na tela continuava:

MAXCC=0000

Antes ele teria comemorado.

Agora começou a perguntar:

E se o arquivo estiver vazio?

E se chegar duplicado?

E se o Db2 retornar -911?

E se o CICS der timeout?

E se dois usuários fizerem isso juntos?

E se MQ não responder?

E se a regra mudar?

E se o sistema estiver lento?

E se um usuário acessar dados de outro?

E se funcionar hoje e quebrar amanhã?

Algoritm sorriu.

— Agora você está testando.

Pegou seu velho pergaminho.

Saiu pelo corredor.

No verso havia uma última frase escrita em tinta desbotada:

“O bom programador escreve caminhos pelos quais o software pode funcionar. O bom tester procura caminhos pelos quais ele pode falhar. O grande engenheiro entende que ambos estão desenhando o mesmo sistema.”

Na manhã seguinte ninguém encontrou o Mestre Algoritm.

Mas sobre a mesa do programador havia uma pequena folha contendo apenas:

IDENTIFY
    RISK

DESIGN
    TEST

EXECUTE
    EVIDENCE

LEARN
    REPEAT

E, escondido no canto inferior, quase como um Easter Egg:

IF PROGRAM-WORKS
    CONTINUE
ELSE
    CALL 'MESTRE-ALGORITM'
END-IF.

O compilador reclamou que MESTRE-ALGORITM não existia.

Naturalmente.

O primeiro teste da manhã havia acabado de encontrar um bug.

sexta-feira, 3 de fevereiro de 2023

🧀 WALLACE & GROMIT E A MÁQUINA QUE FABRICAVA AMBIENTES DE MAINFRAME

 

Bellacosa Mainframe e o ambiente de testes em mainframe

☕ Um Café no Bellacosa Mainframe

🧀 WALLACE & GROMIT E A MÁQUINA QUE FABRICAVA AMBIENTES DE MAINFRAME

COBOL, Db2, IMS, CICS, test data, ambientes efêmeros, service virtualization, CI/CD, DevOps, shift-left, RACF — e o dia em que Wallace descobriu que automatizar o build não adiantava muito quando Gromit precisava esperar três dias pelo ambiente de testes.

Sob a tutela de Wallace & Gromit — porque, no mainframe, construir uma máquina gigantesca para economizar cinco minutos pode parecer absurdo... até descobrirmos que estamos perdendo três dias esperando um DBA.


 



🎬 PRÓLOGO — UMA MANHÃ TRANQUILA EM WEST WALLABY STREET

Wallace acordou com uma ideia brilhante.

Isso normalmente era perigoso.

Ele levantou da cama, apertou alguns botões e anunciou:

— Gromit! Precisamos modernizar o mainframe!

Gromit abaixou o jornal lentamente.

Sobre a mesa havia um programa COBOL.

Nada particularmente assustador.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CRD001.

       PROCEDURE DIVISION.

           EXEC SQL
              SELECT LIMITE_CREDITO,
                     STATUS_CLIENTE
                INTO :WS-LIMITE,
                     :WS-STATUS
                FROM CLIENTE
               WHERE CLIENTE_ID = :WS-ID
           END-EXEC.

Wallace explicou:

— Só precisamos alterar uma regra!

Gromit olhou novamente para o programa.

Parecia simples.

Alterar.

Compilar.

Testar.

Entregar.

Wallace então abriu outro papel.

Para testar aquela pequena alteração seriam necessários:

  • uma região CICS;

  • um subsistema Db2;

  • tabelas atualizadas;

  • dados de clientes;

  • packages;

  • plans;

  • permissões RACF;

  • filas MQ;

  • datasets;

  • programas dependentes;

  • eventualmente IMS;

  • talvez uma API externa;

  • e um ambiente que não estivesse sendo usado por outro projeto.

Gromit fechou os olhos.

A alteração levaria talvez duas horas.

Conseguir tudo necessário para testá-la poderia levar dois dias.

E aqui começa nossa história.

Porque um dos grandes problemas do desenvolvimento moderno no mainframe não está necessariamente no COBOL.

Está no tempo entre:

EU TERMINEI O PROGRAMA

e:

EU CONSIGO TESTAR O PROGRAMA

Pegue seu café.

Wallace já está construindo uma máquina.

Isso nunca termina de maneira simples.



🧀 CAPÍTULO 1 — O COBOL NÃO É NECESSARIAMENTE O GARGALO

Existe uma ideia curiosa no mercado:

Sistemas mainframe são lentos para mudar porque COBOL é antigo.

Isso é uma simplificação perigosa.

Um programador experiente pode fazer rapidamente uma alteração COBOL relativamente pequena.

O verdadeiro fluxo pode ser:

REQUISITO
   ↓
COBOL
   ↓
COMPILE
   ↓
LINK
   ↓
DEPLOY
   ↓
CICS
   ↓
Db2
   ↓
DADOS
   ↓
INTEGRAÇÕES
   ↓
TESTE

Agora imagine que cada seta possa envolver outra equipe.

O programador termina.

Precisa do DBA.

O DBA precisa preparar alguma coisa.

Depois precisa do administrador CICS.

Depois segurança.

Depois alguém precisa restaurar dados.

Depois descobrem que SIT está ocupado.

A aplicação levou duas horas para mudar.

O processo levou quatro dias.

Wallace olharia para isso e imediatamente construiria uma máquina com 47 engrenagens, três chaleiras, duas correias transportadoras e provavelmente um dispensador automático de queijo.

Gromit faria algo melhor:

mediria onde está o tempo perdido.



⏱️ CAPÍTULO 2 — O TEMPO QUE NINGUÉM COLOCA NO DASHBOARD

Suponha que uma mudança tenha este lead time:

Programação ................  4 h
Build ......................  1 h
Teste ......................  3 h

Esperando ambiente ......... 18 h
Esperando dados ............ 10 h
Esperando deploy ........... 12 h
Esperando aprovação ........  8 h

Temos:

TRABALHO EFETIVO ...........  8 h
ESPERA ..................... 48 h

A empresa poderia comprar uma ferramenta que faça o programador produzir código 25% mais rapidamente.

Fantástico.

Talvez economize uma hora.

Ou poderia reduzir pela metade as filas.

Economizaria 24 horas.

É por isso que uma métrica interessante para DevOps é:

Developer Waiting Time

Quanto tempo um desenvolvedor passa esperando alguma coisa necessária para continuar?

Isso pode revelar gargalos invisíveis.

É quase como aplicar conceitos de filas e workload management ao próprio processo de desenvolvimento.

Wallace quer melhorar a máquina.

Gromit primeiro observa onde a máquina está parada.



🏭 CAPÍTULO 3 — DEV, SIT, UAT E A ÚNICA REGIÃO CICS DA VILA

Imagine uma organização com:

DEV
 ↓
SIT
 ↓
UAT
 ↓
PRE-PROD
 ↓
PROD

Parece organizado.

Até descobrirmos que dezenas de desenvolvedores compartilham os mesmos ambientes.

Na segunda-feira:

SIT reservado para Projeto A.

Terça:

indisponível para manutenção.

Quarta:

Projeto B executando regressão.

Quinta:

dados inconsistentes.

Sexta:

release freeze.

Nosso programador COBOL pensa:

Posso testar na próxima semana?

Aqui surge um princípio fundamental:

Ambiente de teste também é recurso computacional.

E recurso computacional pode ser provisionado, configurado, versionado e automatizado.

Essa mudança de pensamento é enorme.



🗄️ CAPÍTULO 4 — Db2: TER O BANCO NÃO SIGNIFICA TER O TESTE

Wallace consegue finalmente um ambiente Db2.

Ele comemora.

Gromit aponta para a tabela CLIENTE.

Há três clientes.

Todos ativos.

Nosso programa precisa testar:

CLIENTE NORMAL
CLIENTE BLOQUEADO
CLIENTE INEXISTENTE
CLIENTE VIP
CONTA ENCERRADA
LIMITE EXCEDIDO
SALDO NEGATIVO
CARTÃO EXPIRADO
CARTÃO ROUBADO
TRANSAÇÃO DUPLICADA

Temos ambiente.

Não temos dados úteis.

Essa diferença é fundamental.

Um banco de desenvolvimento com milhões de registros inúteis pode ser pior para QA do que alguns milhares cuidadosamente preparados.

E simplesmente copiar produção cria outro conjunto de problemas:

LGPD
PCI DSS
dados pessoais
dados financeiros
segredos
volume
permissões
mascaramento
retenção
auditoria

Portanto surge uma disciplina importantíssima:

Test Data Management


🧩 CAPÍTULO 5 — NÃO COPIE APENAS A TABELA CUSTOMER

Suponha:

CUSTOMER
   │
   ├── ACCOUNT
   │      ├── TRANSACTION
   │      └── PAYMENT
   │
   └── CARD
          └── AUTHORIZATION

Você seleciona 100 clientes.

Excelente.

Mas se copiar somente CUSTOMER, sua aplicação pode procurar contas que não existem.

Se copiar ACCOUNT, mas esquecer TRANSACTION, outro teste quebra.

Se copiar CARD, talvez precise preservar relações com autorizações.

Portanto um bom subconjunto de dados precisa manter consistência referencial e semântica.

Não queremos apenas dados.

Queremos uma pequena representação coerente do mundo.


🌳 CAPÍTULO 6 — IMS: AGORA GROMIT DESCOBRIU UMA ÁRVORE

Db2 normalmente nos faz pensar em tabelas.

IMS DB introduz outro modelo mental.

Imagine:

CUSTOMER
│
├── ACCOUNT
│   ├── TRANSACTION
│   └── PAYMENT
│
└── ADDRESS

Aqui podemos estar lidando com estruturas hierárquicas.

O programador COBOL pode encontrar operações DL/I como:

GU
GN
GNP

De maneira simplificada:

GU — Get Unique

Procure algo específico.

GN — Get Next

Continue navegando.

GNP — Get Next within Parent

Continue dentro de determinado contexto hierárquico.

Mas IMS não termina no banco.

Podemos encontrar:

IMS DB
IMS TM
DL/I
DBD
PSB
PCB
SSA
IMS Connect

Para um iniciante, isso parece uma sopa de siglas.

Wallace provavelmente tentaria resolver construindo uma máquina de sopa.

Gromit abriria o manual.

A lição é outra:

Quando virtualizamos ou reproduzimos um ambiente, precisamos compreender suas dependências.

Copiar alguns segmentos pode não reproduzir corretamente a situação necessária ao teste.


🏪 CAPÍTULO 7 — CICS: NENHUM PROGRAMA É UMA ILHA

Nosso programa executa:

EXEC CICS LINK
     PROGRAM('PGM002')
     COMMAREA(WS-COMMAREA)
END-EXEC.

Parece apenas uma chamada.

Mas PGM002 pode acessar Db2.

Depois MQ.

Depois outro programa.

Depois uma API.

Temos:

PGM001
   │
   ▼
PGM002
   │
   ├── Db2
   │
   ├── MQ
   │
   └── PGM003
          │
          ▼
        API

Para testar PGM001, precisamos realmente de tudo isso?

Às vezes sim.

Mas nem sempre.

E aí Wallace encontra uma nova caixa de ferramentas.


🎭 CAPÍTULO 8 — MOCKS, STUBS E SERVICE VIRTUALIZATION

Imagine que PGM001 precise chamar um serviço antifraude.

Em produção:

COBOL
  ↓
CICS
  ↓
MQ
  ↓
ANTIFRAUDE

Mas nosso objetivo atual é testar somente uma regra COBOL.

Podemos substituir temporariamente uma dependência por um comportamento controlado.

Por exemplo:

COBOL
  ↓
SERVIÇO VIRTUAL
  ↓
RESPOSTA CONTROLADA

O serviço virtual pode responder:

{
  "riskScore": 87,
  "decision": "REVIEW"
}

Agora conseguimos testar nosso programa sem depender do sistema antifraude real.

Melhor ainda.

Podemos ordenar:

Agora devolva timeout.

Depois:

Agora devolva erro.

Depois:

Agora envie resposta inválida.

Assim podemos criar:

SUCCESS
TIMEOUT
DENIED
INVALID
DUPLICATE
UNAVAILABLE

Isso é extraordinariamente útil.


💣 CAPÍTULO 9 — GROMIT DESCOBRE QUE QUEBRAR O SISTEMA TAMBÉM É TESTAR

Testar não significa verificar apenas:

ENTRADA CORRETA → RESULTADO CORRETO

Precisamos descobrir:

O QUE ACONTECE QUANDO ALGO DÁ ERRADO?

Imagine:

TRANSACTION
     │
     ▼
   CICS
     │
     ▼
   COBOL
     │
     ├── Db2 → SQLCODE -911
     │
     ├── MQ  → problema na fila
     │
     └── API → HTTP 503

Como o programa reage?

Faz rollback?

Tenta novamente?

Duplica uma transação?

Perde informação?

Produz mensagem compreensível?

Grava evidência suficiente?

Isso nos leva aos testes negativos.

Eles são particularmente valiosos porque muitos incidentes graves não acontecem durante o happy path.

Acontecem nas exceções.


🥚 EASTER EGG — 03:17

Wallace finalmente termina sua máquina.

Relógio:

03:17.

Gromit olha preocupado.

A API retorna timeout.

O MQ começa a acumular mensagens.

Db2 apresenta contenção.

CICS espera.

Wallace pergunta:

— Por que ninguém testou isso?

Porque todos testaram:

HTTP 200
SQLCODE 0
MQ OK
CICS OK

Ninguém perguntou:

E se três coisas falharem juntas?

O incidente das 03:17 nasceu exatamente no lugar onde terminava o happy path.


⚡ CAPÍTULO 10 — E SE O DESENVOLVEDOR PUDESSE PEDIR UM MAINFRAME?

Aqui chegamos a uma mudança conceitual enorme.

Modelo tradicional:

DEVELOPER
    ↓
TICKET
    ↓
SYSPROG
    ↓
DBA
    ↓
SECURITY
    ↓
CICS ADMIN
    ↓
WAIT
    ↓
ENVIRONMENT

Agora imagine:

DEVELOPER
    ↓
SELF-SERVICE
    ↓
TEMPLATE APROVADO
    ↓
PROVISION
    ↓
AMBIENTE DEV/TEST

Não estamos falando de entregar produção para o desenvolvedor.

Estamos falando de criar ambientes isolados e governados para desenvolvimento e testes.

O conceito pode incluir tecnologias de virtualização e ofertas destinadas a proporcionar ambientes z/OS de desenvolvimento e teste de maneira muito mais rápida.

A pergunta deixa de ser:

Qual LPAR está livre?

E passa a ser:

Qual configuração de ambiente eu preciso?

Essa mudança é gigantesca.


🧀 CAPÍTULO 11 — WALLACE INVENTA O MAINFRAME DESCARTÁVEL

Não descarte o IBM Z!

Calma.

Estamos falando do ambiente de desenvolvimento.

Imagine:

CREATE
  ↓
TEST
  ↓
COLLECT EVIDENCE
  ↓
DESTROY

Ou:

TEMPLATE
   ↓
ENVIRONMENT A
ENVIRONMENT B
ENVIRONMENT C

Cada squad pode trabalhar com isolamento muito maior.

Isso nos aproxima do conceito de ambientes efêmeros.

O ambiente nasce para cumprir determinada finalidade.

Executamos os testes.

Coletamos logs e evidências.

Depois ele pode ser removido.

Amanhã outro ambiente é criado novamente a partir de uma configuração conhecida.


🧬 CAPÍTULO 12 — INFRASTRUCTURE AS CODE ENCONTRA O COBOL

Wallace adora infraestrutura.

Especialmente se possuir alavancas.

DevOps prefere arquivos declarativos, APIs e automação.

Conceitualmente:

environment:
  zos: enabled
  cics: enabled
  db2: enabled
  ims: enabled
  mq: enabled

Não estou dizendo que essa configuração fictícia cria magicamente um ambiente real.

Ela ilustra a ideia.

A infraestrutura deixa de existir apenas como conhecimento informal:

Pergunte ao José porque ele sabe configurar.

E passa a ser descrita de maneira reproduzível.

Isso gera:

padronização
repetibilidade
auditabilidade
automação
velocidade

🚀 CAPÍTULO 13 — RAPID PROTOTYPING

Agora alguém propõe:

Vamos expor esta transação CICS através de REST.

Antes:

REUNIÃO
 ↓
TICKET
 ↓
AMBIENTE
 ↓
CONFIGURAÇÃO
 ↓
TESTE

Com um laboratório disponível:

CICS
 ↓
COBOL
 ↓
Db2
 ↓
API
 ↓
JSON
 ↓
POSTMAN

Podemos experimentar.

Não funcionou?

Reconfiguramos.

Quebrou?

Restauramos.

A ideia é importante porque experimentação precisa ser barata.

Quando cada tentativa exige uma semana de burocracia, as pessoas naturalmente experimentam menos.


🔬 CAPÍTULO 14 — SHIFT LEFT NÃO É EMPURRAR UMA CAIXINHA NO POWERPOINT

Você provavelmente já viu:

DEV → TEST → QA → UAT → PROD

E alguém desenhou uma seta enorme:

← SHIFT LEFT

Pronto.

Transformação digital concluída.

Não.

Shift left significa descobrir problemas mais cedo.

Idealmente:

DEV
 ↓
UNIT TEST
 ↓
INTEGRATION TEST
 ↓
SYSTEM TEST
 ↓
UAT
 ↓
PROD

Quanto mais cedo encontramos:

erro de lógica
SQL incorreto
dependência quebrada
contrato incompatível
timeout
problema de dados

menor tende a ser o custo de correção.

Encontrar um erro cinco minutos depois de escrevê-lo é muito diferente de encontrá-lo durante uma janela de implantação.

Ou às 03:17.


🏭 CAPÍTULO 15 — GROMIT CONSTRÓI UM PIPELINE

Agora tudo começa a se encaixar.

git push
   │
   ▼
BUILD
   │
   ▼
STATIC ANALYSIS
   │
   ▼
UNIT TEST
   │
   ▼
PROVISION ENVIRONMENT
   │
   ▼
DEPLOY
   │
   ▼
TEST DATA
   │
   ▼
INTEGRATION TEST
   │
   ▼
REGRESSION
   │
   ▼
EVIDENCE
   │
   ▼
PROMOTION

Perceba uma diferença importantíssima.

O ambiente entrou no pipeline.

Antes o pipeline dizia:

Aqui está o executável.

Agora ele pode dizer:

Aqui está o software, o ambiente onde foi validado, os testes executados e suas evidências.

Isso é muito mais poderoso.


🗃️ CAPÍTULO 16 — MAS E O Db2?

Aqui existe uma armadilha clássica.

Aplicação:

APP V1

Banco:

SCHEMA V1

Nova aplicação:

APP V2

Mas ela depende de:

SCHEMA V2

Portanto DevOps não pode cuidar apenas do .CBL.

Precisamos pensar em:

DDL
SQL
BIND
PACKAGE
PLAN
SCHEMA
TEST DATA
MIGRATION
ROLLBACK

Banco de dados também possui ciclo de vida.

Isso é Database DevOps.

E atenção:

automação não significa:

Todo mundo pode executar ALTER em produção.

É justamente o contrário.

Uma boa automação transforma regras em guardrails.


🔐 CAPÍTULO 17 — WALLACE QUASE REMOVE O RACF

Wallace vê todos esses processos automatizados.

— Excelente! Agora todo mundo pode fazer tudo!

Gromit olha horrorizado.

Não.

Self-service não significa ausência de controle.

Continuamos precisando de:

RACF
SAF
least privilege
segregation of duties
audit trail
approvals
data protection
logging
evidence

A diferença é:

Antes

controle = pessoas executando tarefas repetitivas

Depois

controle = políticas + automação + evidência

Esse é um ponto essencial.

DevOps não elimina governança.

DevOps pode transformar governança em código e processos repetíveis.


🧠 CAPÍTULO 18 — MODERNIZAR NÃO SIGNIFICA JOGAR O COBOL FORA

Talvez esta seja a maior lição da aventura.

Durante anos ouvimos modernização descrita assim:

COBOL
 ↓
LEGACY
 ↓
REWRITE
 ↓
CLOUD

Mas existe outra possibilidade:

COBOL
CICS
Db2
IMS
MQ
 ↓
MODERN DEVELOPMENT EXPERIENCE

Podemos manter aplicações extremamente valiosas e modernizar tudo ao redor:

Git
CI/CD
APIs
automated testing
test virtualization
observability
DevSecOps
Infrastructure as Code
automated provisioning
modern IDEs

Isso é modernização sem obrigatoriamente reescrever tudo.


🔭 CAPÍTULO 19 — O MAINFRAME NÃO É MAIS APENAS O DESTINO

Esta é uma mudança profunda.

No modelo antigo:

PIPELINE
   ↓
MAINFRAME

O mainframe era o lugar onde o resultado finalmente chegava.

No modelo moderno:

             PIPELINE
                │
     ┌──────────┼──────────┐
     ▼          ▼          ▼
   BUILD       TEST     ENVIRONMENT
     │          │          │
     └──────────┼──────────┘
                ▼
              z/OS

O próprio ambiente mainframe participa do ciclo.

Provisionamento.

Build.

Teste.

Deploy.

Validação.

Evidência.

Tudo pode integrar uma cadeia de automação.


📊 CAPÍTULO 20 — O DASHBOARD QUE WALLACE ESQUECEU

Estamos acostumados a observar:

CPU
MSU
I/O
latência
throughput
availability
response time

Tudo correto.

Mas DevOps precisa olhar também:

lead time
deployment frequency
change failure
recovery time
test execution time
environment provisioning time
developer waiting time

Imagine descobrir:

Lead time ............... 120 horas

Programando ............. 12
Testando ................ 10

Esperando ambiente ...... 38
Esperando dados ......... 20
Esperando deploy ........ 25
Esperando aprovação ..... 15

Temos:

TRABALHO = 22 horas
ESPERA   = 98 horas

Wallace estava tentando construir uma máquina para fazer COBOL 30% mais rápido.

Gromit apontou para as 98 horas.

Aí Wallace finalmente entendeu.


🛠️ CAPÍTULO 21 — PASSO A PASSO PARA COMEÇAR

Se você está começando em COBOL, não tente construir toda essa arquitetura amanhã.

Comece pequeno.

PASSO 1 — Mapeie uma aplicação

Descubra:

COBOL
 ↓
CICS?
 ↓
Db2?
 ↓
IMS?
 ↓
MQ?
 ↓
API?

PASSO 2 — Mapeie dependências

Pergunte:

Para testar este programa, do que realmente preciso?

PASSO 3 — Separe teste unitário de integração

Nem todo teste precisa do universo inteiro.

PASSO 4 — Identifique dados necessários

Crie casos:

NORMAL
BOUNDARY
INVALID
ERROR
TIMEOUT
DUPLICATE

PASSO 5 — Automatize o build

Compile sempre da mesma maneira.

PASSO 6 — Automatize testes repetitivos

Se alguém executa exatamente os mesmos passos diariamente, existe um ótimo candidato à automação.

PASSO 7 — Crie evidências

Guarde:

build
versão
logs
resultado
dados
timestamp

PASSO 8 — Meça espera

Talvez o maior gargalo não esteja onde todos imaginavam.

PASSO 9 — Virtualize dependências caras

Nem todo sistema externo precisa estar presente em todo teste.

PASSO 10 — Automatize ambientes gradualmente

Comece pelo que produz maior espera.


💡 CAPÍTULO 22 — CURIOSIDADES PARA O PADAWAN COBOL

Primeira curiosidade:

COBOL ser uma linguagem antiga não significa que todo processo ao redor dele precise continuar antigo.

Segunda:

Um programa de 200 linhas pode depender de uma arquitetura com dezenas de componentes.

Terceira:

Mais dados de teste não significa necessariamente melhores testes.

Quarta:

Conseguir provocar um erro propositalmente é uma habilidade extremamente valiosa de QA.

Quinta:

Automação não serve apenas para fazer alguma coisa mais rapidamente.

Ela também serve para fazer alguma coisa da mesma maneira todas as vezes.

Sexta:

Ambiente reproduzível é documentação executável.

Se conseguimos reconstruí-lo automaticamente, sabemos muito mais sobre ele do que quando sua configuração vive apenas na cabeça de algumas pessoas.


🧀 EPÍLOGO — WALLACE FINALMENTE APERTA O BOTÃO

Depois de dias trabalhando, Wallace apresenta sua nova invenção.

Uma máquina gigantesca ocupa toda a garagem.

Gromit observa.

Wallace aperta o botão.

Engrenagens começam a girar.

Git
 ↓
Build
 ↓
COBOL
 ↓
Test
 ↓
Environment
 ↓
CICS
 ↓
Db2
 ↓
IMS
 ↓
MQ
 ↓
Regression
 ↓
Evidence

Uma pequena luz verde acende.

Na tela:

BUILD SUCCESSFUL

UNIT TESTS:       PASS
INTEGRATION:      PASS
NEGATIVE TESTS:   PASS
REGRESSION:       PASS

ENVIRONMENT DESTROYED

Wallace sorri.

— Pronto, Gromit! Automatizamos o mainframe!

Gromit aponta para outra tela:

AVERAGE DEVELOPER WAITING TIME

BEFORE: 31 HOURS
AFTER:   47 MINUTES

Wallace finalmente percebe que aquela era a informação realmente importante.

Eles não tornaram o COBOL moderno.

O COBOL já estava fazendo aquilo para que havia sido criado.

Não substituíram Db2.

Não destruíram IMS.

Não aposentaram CICS.

Não migraram tudo para alguma tecnologia da moda apenas para poder colocar a palavra "modernização" num PowerPoint.

Eles fizeram algo talvez mais inteligente.

Modernizaram o caminho entre a ideia do programador e a evidência de que aquela ideia funciona.

Essa é uma das grandes fronteiras do DevOps no mainframe.

O problema não é necessariamente:

"Como fazemos COBOL parecer uma aplicação cloud?"

Talvez a pergunta correta seja:

"Como permitimos que uma aplicação COBOL, CICS, IMS ou Db2 participe de uma experiência moderna de desenvolvimento sem destruir as qualidades que fizeram esse ecossistema sobreviver por décadas?"

E a resposta passa por:

AUTOMAÇÃO
+
SELF-SERVICE
+
TEST DATA
+
SERVICE VIRTUALIZATION
+
SHIFT LEFT
+
CI/CD
+
AMBIENTES REPRODUZÍVEIS
+
SEGURANÇA
+
OBSERVABILIDADE
+
EVIDÊNCIA

Wallace guarda as ferramentas.

Gromit prepara o chá.

O programador COBOL faz um commit.

O pipeline começa a trabalhar.

Nenhum chamado precisa ser aberto apenas para descobrir se uma pequena alteração funciona.

E em algum lugar dentro do datacenter, silenciosamente, o relógio muda para:

03:16

Gromit olha para ele.

Espera.

03:17

Nada acontece.

Nenhum pager toca.

Nenhuma fila explode.

Nenhum operador corre.

Nenhum programador é acordado.

Gromit toma mais um gole de chá.

Talvez aquele tenha sido o melhor teste de todos.


☕ MORAL DO CAFÉ

Modernizar mainframe não significa necessariamente substituir aquilo que funciona.

Às vezes significa eliminar tudo aquilo que obriga pessoas altamente qualificadas a ficarem esperando.

Porque existe uma diferença enorme entre:

MAINFRAME LEGACY

e:

PROCESSO LEGACY

Não confunda os dois.

O IBM Z pode processar bilhões de transações.

CICS pode responder em frações de segundo.

Db2 pode atender workloads gigantescos.

IMS pode sustentar aplicações críticas durante décadas.

E mesmo assim...

o programador pode ficar três dias esperando um ambiente de teste.

Nesse caso, meu jovem padawan COBOL, talvez a coisa mais lenta do sistema não esteja rodando no mainframe.

Talvez esteja rodando no processo.

E é justamente aí que Wallace & Gromit começariam a construir a próxima máquina.

Welcome to the Mainframe. ☕🧀

domingo, 14 de agosto de 2022

O Mágico de Oz Entra no CPD — O Dia em que Dorothy Descobriu que “Funcionou na Minha Máquina” Não Vale como Evidência de Teste

 
Bellacosa Mainframe e os testes em software mainframe

Um Café no Bellacosa Mainframe

O Mágico de Oz Entra no CPD — O Dia em que Dorothy Descobriu que “Funcionou na Minha Máquina” Não Vale como Evidência de Teste

Ou: como Requirements, Unit Test, Integration, System Test, UAT, Test Data, Boundary Value, Bug Report, Severity, Priority, Regression e um programador COBOL iniciante seguiram pela Estrada de Tijolos Amarelos até descobrir que, atrás da cortina, qualidade não é mágica — é método

Há uma cena clássica em O Mágico de Oz: Dorothy e seus companheiros atravessam perigos, florestas, campos de papoulas, bruxas e criaturas estranhas para finalmente chegar à Cidade das Esmeraldas.

Todos esperam encontrar um ser extraordinário.

Uma entidade quase divina.

O Grande e Poderoso Oz.

Então Toto puxa uma cortina.

E atrás dela existe apenas um sujeito comum operando alavancas.

No mundo dos testes de software acontece algo parecido.

Durante muito tempo, especialmente para quem começa a programar, parece existir uma espécie de magia chamada:

“QA testou.”

O programador entrega o código.

Alguém misterioso em outro andar executa alguma coisa.

Alguns dias depois chega um chamado:

“Bug encontrado.”

E então começa o ritual.

— Aqui funciona.

— Em QA não.

— Qual ambiente?

— QA.

— Qual massa?

— A massa de QA.

— Qual erro?

— Deu erro.

Nesse momento, Toto deveria entrar no CPD e puxar a cortina.

Porque software testing não é mágica.

Não há fumaça.

Não há espelhos.

E, principalmente, não existe prestidigitação capaz de transformar código não testado em software confiável.

Existe método.

Existe planejamento.

Existe risco.

Existe evidência.

Existe engenharia.

E é exatamente isso que vamos explorar.



Prólogo — Dorothy recebe seu primeiro programa COBOL

Imagine Dorothy recém-contratada como programadora COBOL.

Ela recebe uma especificação:

Clientes com idade entre 18 e 60 anos podem aderir ao produto.

Ela escreve:

IF WS-IDADE >= 18 AND WS-IDADE <= 60
    MOVE 'S' TO WS-ELEGIVEL
ELSE
    MOVE 'N' TO WS-ELEGIVEL
END-IF

Compila.

Executa com:

IDADE = 30

Resultado:

ELEGIVEL = S

Dorothy sorri.

— Pronto.

O Espantalho, representando aquele colega que ainda procura um cérebro para requisitos, pergunta:

— Você testou?

— Sim.

— Quantas idades?

— Uma.

O Homem de Lata olha para o código, sente uma pequena dor no coração que ainda não possui e pergunta:

— E 18?

Dorothy testa.

Funciona.

O Leão Covarde pergunta:

— E 60?

Funciona.

Toto late.

Alguém resolve testar:

17
19
59
61
-1
999
ABC
vazio

E eis que começa a verdadeira história.

Porque testar não é escolher um exemplo que funciona.

Testar é procurar sistematicamente condições nas quais a solução pode deixar de funcionar.

Esse é o primeiro tijolo amarelo da nossa estrada.



1. O que é software testing de verdade?

Software testing é o processo de avaliar um software para verificar se ele atende aos requisitos esperados e para identificar defeitos, comportamentos incorretos e riscos.

Uma definição parece simples.

Mas existe um detalhe quase filosófico:

Testing não prova que software não possui defeitos.

Testing encontra evidências de que determinados comportamentos funcionam — ou não funcionam — sob determinadas condições.

Imagine um programa com bilhões de combinações possíveis de entrada.

Você jamais testará todas.

Portanto testing é também uma disciplina de amostragem inteligente de riscos.

Um bom tester pensa:

Onde esse negócio provavelmente vai quebrar?

Um excelente programador pensa assim também.


2. QA, QC e Testing — três personagens diferentes na mesma estrada

As notas que a
nalisamos fazem uma distinção importante entre Quality Assurance, Quality Control e Testing.

QA — Quality Assurance

QA olha predominantemente para o processo.

Pergunta:

Estamos trabalhando de uma maneira que reduz a chance de produzir defeitos?

Isso envolve:

  • padrões;

  • processos;

  • revisões;

  • métodos;

  • governança;

  • critérios;

  • documentação.

QA tenta evitar que Dorothy saia caminhando pela estrada errada antes mesmo da viagem começar.

QC — Quality Control

Quality Control olha para o produto entregue.

Pergunta:

Aquilo que foi construído está correto?

É inspeção e controle.

Testing

Testing é a atividade prática de exercitar o sistema buscando evidências.

Podemos resumir:

QA       → evitar defeitos
QC       → detectar defeitos no produto
Testing  → executar verificações sobre o sistema

Não são exatamente sinônimos.


3. Error, defect, bug e failure — a família que ninguém quer conhecer

Aqui temos outra distinção extremamente útil.

Imagine que Dorothy deveria escrever:

IF SALDO >= VALOR

Mas escreveu:

IF SALDO > VALOR

Isso é um erro humano.

O erro gerou um problema no código.

Esse problema é um defect.

Quando o cliente possui saldo exatamente igual ao valor do saque e o sistema rejeita a operação, temos uma failure, isto é, a manifestação observável do defeito.

Simplificando:

ERROR
  ↓
DEFECT
  ↓
FAILURE

“Bug” é frequentemente usado como sinônimo de defect.

Curiosidade: a história popular associa o termo bug ao inseto encontrado no Harvard Mark II em 1947. Mas engenheiros já usavam “bug” para falhas técnicas décadas antes. Grace Hopper ajudou a tornar o episódio famoso, não a inventar a palavra.

Easter egg mainframe número 1: qualquer programador que já caçou um abend às três da manhã sabe que alguns bugs realmente parecem vivos.


4. SDLC — o software não começa no COBOL

Outro erro clássico do iniciante é imaginar:

Especificação
↓
COBOL
↓
Produção

Na realidade, existe um ciclo maior, o Software Development Life Cycle.

De maneira simplificada:

Requirements
↓
Design
↓
Development
↓
Testing
↓
Deployment
↓
Maintenance

O código é apenas uma parte.

Em mainframe isso é ainda mais evidente.

Você pode alterar 20 linhas COBOL que dependem de:

  • Copybook;

  • JCL;

  • Db2;

  • VSAM;

  • CICS;

  • MQ;

  • RACF;

  • scheduler;

  • arquivos recebidos;

  • programas chamados;

  • programas chamadores.

O código parece local.

O impacto pode ser interestelar.


5. Waterfall, V-Model, Iterative, Incremental, Spiral e Prototype

As imagens apresentam vários modelos de desenvolvimento.

Não precisamos transformar isso numa aula acadêmica infinita, mas vale entender o espírito.

Waterfall

Modelo sequencial.

Requirement
↓
Design
↓
Coding
↓
Testing
↓
Deployment

Funciona bem quando requisitos são estáveis.

Problema:

Se você descobre no final que o requisito estava errado, o custo da correção pode ser enorme.

V-Model

Esse merece atenção especial.

De um lado:

Requirements
System Design
Architecture
Module Design
Coding

Do outro:

Unit Test
Integration Test
System Test
Acceptance Test

A ideia central é espetacular:

o teste correspondente deve ser pensado junto com a etapa que o originou.

Por exemplo:

Business Requirement ←→ Acceptance Test
System Design         ←→ System Test
Architecture          ←→ Integration Test
Module Design         ←→ Unit Test

Isso antecipa o conceito moderno de Shift Left.

Ou seja:

Não espere terminar tudo para pensar em qualidade.


6. STLC — a estrada de tijolos amarelos dos testes

O Software Testing Life Cycle normalmente passa por etapas semelhantes a:

Requirement Analysis
↓
Test Planning
↓
Test Case Development
↓
Test Environment Setup
↓
Test Execution
↓
Defect Reporting
↓
Test Closure

Parece burocrático.

Mas cada etapa responde uma pergunta.

Requirement Analysis

O que precisamos verificar?

Test Planning

Como vamos verificar?

Test Case Development

Quais cenários serão usados?

Environment Setup

Onde vamos executar?

Test Execution

O que realmente aconteceu?

Defect Management

Como registrar e acompanhar problemas?

Closure

Quando podemos declarar que o ciclo terminou?

Isso é tudo menos prestidigitação.


7. A primeira grande armadilha: requisitos ambíguos

Imagine a regra:

Cliente pode transferir até R$ 10.000 por dia.

Parece clara.

Não é.

Um tester imediatamente pergunta:

  • Por CPF ou conta?

  • Dia civil ou últimas 24 horas?

  • PIX e TED compartilham limite?

  • Transferência agendada conta quando é criada ou executada?

  • Limite inclui tarifa?

  • R$ 10.000 exatamente é permitido?

  • Cliente PJ possui a mesma regra?

Aí percebemos uma coisa linda:

um bom tester encontra defeitos antes do software existir.

Ele encontra defeitos no requisito.

E defeito encontrado cedo costuma custar muito menos.


8. Entry Criteria e Exit Criteria

Outro conceito essencial.

Entry Criteria

Antes de começar os testes, certas condições precisam estar atendidas.

Por exemplo:

build disponível
ambiente ativo
database carregado
massa pronta
requisitos aprovados

Se o Db2 está indisponível, o teste talvez fique:

BLOCKED

Isso é diferente de:

FAILED

O sistema não falhou.

O teste não pôde ser executado.

Exit Criteria

Também precisamos definir quando parar.

Exemplo:

100% testes críticos executados
0 blockers abertos
0 critical defects abertos
95% dos casos aprovados
riscos residuais aceitos

Sem isso, “terminamos os testes” significa apenas:

Alguém cansou.


9. Pirâmide de testes — não coloque tudo no topo

A pirâmide clássica sugere:

           E2E
        Integration
     Unit Unit Unit

Ou:

  • muitos testes unitários;

  • menos testes de integração;

  • poucos testes E2E.

Por quê?

Testes unitários tendem a ser:

  • rápidos;

  • baratos;

  • estáveis;

  • fáceis de automatizar.

Testes E2E geralmente são:

  • lentos;

  • caros;

  • dependentes de ambientes;

  • vulneráveis a falhas externas.

Imagine testar um PIX apenas através do aplicativo final.

Se falhar, onde está o problema?

Mobile?
API?
Gateway?
MQ?
CICS?
COBOL?
Db2?
Rede?
RACF?

Agora imagine testes menores cobrindo cada camada.

Diagnóstico fica muito mais fácil.


10. Unit Testing — teste a peça antes da máquina inteira

Em COBOL, uma unidade pode ser um programa, rotina ou lógica isolada.

Exemplo:

COMPUTE WS-JUROS =
    WS-CAPITAL * WS-TAXA / 100

Teste:

Capital = 1000
Taxa = 10
Esperado = 100

Depois:

Capital = 0
Taxa = 10
Esperado = 0

Depois:

Taxa = 0

E assim por diante.

O objetivo é testar a lógica sem depender do universo inteiro.


11. Integration Testing — onde os monstros geralmente moram

Integração é onde módulos conversam.

No mainframe isso pode significar:

COBOL ↔ Db2
COBOL ↔ VSAM
CICS ↔ COBOL
CICS ↔ MQ
MQ ↔ Java
API ↔ z/OS Connect

Muitos defeitos aparecem exatamente nas fronteiras.

Exemplos:

  • tamanho de campo diferente;

  • packed decimal interpretado incorretamente;

  • copybook desatualizado;

  • encoding ASCII/EBCDIC;

  • commit inconsistente;

  • timeout;

  • JSON mal formado;

  • campo obrigatório ausente.

Dois módulos podem funcionar perfeitamente isolados e falhar miseravelmente juntos.

O Espantalho chamaria isso de “falta de cérebro”.

Nós chamamos de integração.


12. System Testing

Agora testamos o sistema integrado.

Exemplo bancário:

Login
↓
Consulta saldo
↓
PIX
↓
Autenticação
↓
Débito
↓
Registro
↓
Comprovante

Não estamos mais testando apenas uma rotina COBOL.

Estamos testando comportamento de negócio.


13. Acceptance Testing e UAT

Aqui entra o usuário ou área de negócio.

A pergunta muda.

QA pergunta:

O sistema atende à especificação?

Negócio pergunta:

Isso serve para trabalhar?

Um sistema pode estar tecnicamente correto e operacionalmente ser um desastre.

Por isso UAT é crucial.

Easter egg número 2: Oz pode dizer que a máquina funciona perfeitamente. Dorothy ainda precisa descobrir se ela realmente consegue levá-la de volta ao Kansas.


14. Functional Testing — o que o sistema faz?

Functional testing verifica WHAT.

Exemplo:

Usuário correto + senha correta
→ login deve funcionar

Outro:

Saldo = 1000
Saque = 200
→ saldo final = 800

Estamos testando comportamento esperado.


15. Positive e Negative Testing

Positive Testing

Usamos entradas válidas.

idade = 30

Esperamos sucesso.

Negative Testing

Usamos entradas inválidas.

idade = -10
idade = ABC
campo vazio

Aqui existe um ponto muito importante.

O objetivo não é simplesmente provocar erro.

É verificar se o sistema trata o erro corretamente.

Bom software não é aquele que nunca recebe entrada ruim.

É aquele que sabe lidar com ela.


16. Non-functional Testing — quão bem funciona?

Aqui muda tudo.

Functional pergunta:

Faz?

Non-functional pergunta:

Faz bem?

Exemplos:

  • performance;

  • segurança;

  • confiabilidade;

  • escalabilidade;

  • usabilidade;

  • compatibilidade;

  • acessibilidade.

Login funcionar é funcional.

Login demorar 47 segundos é problema não funcional.


17. Performance, Load, Stress, Spike e Volume

Esses termos frequentemente são confundidos.

Performance Testing

Avalia comportamento de desempenho.

Métricas:

response time
throughput
latency
CPU
memory
I/O

No z/OS podemos acrescentar:

CPU time
elapsed time
service units
EXCP
Db2 getpages
lock waits
CICS response time
WLM behavior

Load Testing

Carga esperada.

Exemplo:

10.000 transações/minuto

Stress Testing

Carga acima do esperado.

Objetivo:

Onde quebra e como quebra?

Spike Testing

Carga sobe abruptamente.

Black Friday é o exemplo perfeito.

Volume Testing

Muito dado.

Uma query maravilhosa com 5 mil registros pode virar carvão com 500 milhões.


18. Security Testing

Segurança não é apenas verificar se o usuário certo entra.

É verificar se o usuário errado fica fora.

Exemplo:

Usuário autorizado → permitido
Usuário não autorizado → negado

No mainframe:

RACF profiles
dataset access
CICS transactions
Db2 privileges
USS permissions
started tasks

Um teste de autorização deve testar allow e deny.

Testar apenas aquilo que deveria funcionar deixa metade da segurança invisível.


19. Black Box Testing

Black box trata o sistema como caixa fechada.

INPUT
  ↓
SYSTEM
  ↓
OUTPUT

O tester não precisa conhecer implementação.

Exemplo:

saldo 100
saque 30
esperado 70

Pode existir COBOL, Java, PL/I ou um anão verde calculando lá dentro.

Para black box pouco importa.


20. White Box Testing

Agora conhecemos o código.

Queremos verificar caminhos internos.

Considere:

IF SALDO >= VALOR
    IF CONTA-ATIVA = 'S'
        PERFORM EFETUAR-SAQUE
    END-IF
END-IF

Temos combinações:

saldo suficiente / conta ativa
saldo suficiente / conta inativa
saldo insuficiente / conta ativa
saldo insuficiente / conta inativa

Isso envolve:

  • statement coverage;

  • branch coverage;

  • condition coverage;

  • path testing.

E aqui vale um alerta:

100% de cobertura não significa ausência de bugs.


21. Equivalence Partitioning — teste representantes

Suponha:

idade válida = 18 até 60

Temos três grandes classes:

<18
18–60
>60

Em vez de testar todos os números, podemos inicialmente testar representantes:

10
30
70

Isso reduz drasticamente quantidade de testes sem jogar cobertura pela janela.


22. Boundary Value Analysis — é nas bordas que os gremlins moram

A técnica favorita de quem já viu muito bug.

Para:

18 ≤ idade ≤ 60

teste:

17
18
19
59
60
61

Por quê?

Porque humanos escrevem:

>

quando deveriam escrever:

>=

E vice-versa.

Aliás, nas próprias notas havia uma inconsistência divertida no exemplo de limite superior.

Um dos quadros rotulava valores máximos de maneira incorreta.

O que nos entrega o melhor easter egg deste artigo:

até uma apostila sobre testes precisa de teste.

Toto aprovou.


23. Decision Table Testing

Excelente para regra de negócio complexa.

Imagine aprovação:

Cliente ativo?
Score bom?
Renda suficiente?

Tabela:

AtivoScoreRendaAprovar
SSSS
SSNN
SNSN
NSSN

Isso ajuda a enxergar combinações esquecidas.


24. State Transition Testing

Alguns sistemas têm estados.

Exemplo:

ATIVO
↓
BLOQUEADO
↓
DESBLOQUEADO
↓
CANCELADO

Agora precisamos testar transições.

Pode existir:

ATIVO → BLOQUEADO

válida.

Mas talvez:

CANCELADO → ATIVO

seja proibida.

Isso aparece muito em:

  • cartões;

  • contas;

  • pedidos;

  • contratos;

  • tickets;

  • workflows.


25. Error Guessing — experiência com cicatrizes

Essa técnica parece informal, mas é poderosa.

O tester experiente pensa:

Já vi isso explodir antes.

Então testa:

zero
null
vazio
duplicado
máximo
mínimo
29/02
31/12
arquivo vazio
registro duplicado
caractere especial

É conhecimento acumulado através de incidentes.

O Leão ganha coragem.

O Homem de Lata ganha coração.

O tester ganha trauma produtivo.


26. Test Case — roteiro da investigação

Um caso de teste deve conter coisas como:

ID
Title
Objective
Preconditions
Test Data
Steps
Expected Result
Actual Result
Status
Remarks

Exemplo:

TC-PIX-001

Objetivo:
Validar PIX com saldo suficiente.

Pré-condição:
Conta ativa.
Saldo = 1000.

Entrada:
PIX = 200.

Esperado:
Saldo final = 800.
Transação registrada.
Comprovante emitido.

O segredo está no Expected Result.


27. Nunca teste sem saber o que deveria acontecer

Esse é um erro impressionantemente comum.

O sujeito executa algo e diz:

Vamos ver o resultado.

Isso é experimento exploratório.

Pode ser útil.

Mas não é um caso formal de validação.

Se você não sabe previamente o esperado, como saberá se o resultado está correto?


28. Test Data — massa de teste não é detalhe

Massa de teste determina qualidade do teste.

Pode ser:

  • válida;

  • inválida;

  • limite;

  • extrema;

  • normal;

  • sintética;

  • mascarada.

Uma coisa importante:

muito dado não significa boa massa.

Um milhão de registros iguais cobre pouco.

Cinquenta registros cuidadosamente escolhidos podem cobrir enorme variedade de risco.


29. Production Data — cuidado com Dorothy carregando o banco inteiro para QA

Copiar produção para teste pode parecer tentador.

Mas pode existir:

  • CPF;

  • telefone;

  • endereço;

  • cartão;

  • dados financeiros;

  • informações pessoais.

Por isso entram:

masking
anonymization
tokenization
synthetic data

Usar dados reais sem proteção pode transformar um projeto de testing em incidente de segurança.

E essa bruxa ninguém quer encontrar.


30. Test Environment — o ambiente também é parte do teste

Um ambiente inclui muito mais que servidor.

Pode envolver:

hardware
software
network
database
tools
data
people
documentation

No mainframe:

LPAR
z/OS
CICS
Db2
MQ
RACF
VSAM
LOADLIB
PROCLIB
JCL
scheduler
TCP/IP

O programa pode estar certo e falhar porque a STEPLIB aponta para versão antiga.

Não é lenda urbana.

É terça-feira.


31. Dev, QA, UAT, Staging, Production

Fluxo comum:

DEV
↓
QA
↓
STAGING
↓
PROD

Empresas reais inventam variações:

DEV
SIT
INT
QA
UAT
PREPROD
PROD

O importante é isolamento, rastreabilidade e controle.

Quanto mais próximo de produção, maior deveria ser a fidelidade do ambiente.


32. Test Execution

Chegamos ao momento em que o teste roda.

Fluxo:

Select Test
↓
Prepare Data
↓
Execute
↓
Compare Expected vs Actual
↓
Report Defect
↓
Update Status
↓
Retest

Estados comuns:

Not Executed
Pass
Fail
Blocked
Skipped
Retest

Fail não é Blocked.

Essa diferença pode evitar uma tarde inteira de reunião inútil.


33. Defect Life Cycle

Bug não nasce e desaparece instantaneamente.

Fluxo típico:

New
↓
Assigned
↓
Open
↓
In Progress
↓
Resolved
↓
Retest
↓
Verified
↓
Closed

Se continuar:

Reopen

“Fixed by developer” não significa “Closed”.

A correção precisa ser verificada.


34. Severity versus Priority

Esse conceito merece tatuagem temporária de projeto.

Severity mede impacto técnico.

Priority mede urgência de correção.

Imagine um erro ortográfico na home.

Severity:

LOW

Mas o CEO vai demonstrar o sistema em dez minutos.

Priority:

CRITICAL

Outro caso:

Bug grave numa funcionalidade que será desativada amanhã.

Severity alta.

Priority talvez baixa.

Portanto:

Severity ≠ Priority

Nas páginas analisadas havia também duas convenções:

P0-P3

e:

P1-P4

Ambas existem no mercado.

A empresa precisa definir sua escala.


35. Bug Reporting — “não funciona” não é relatório

Bug ruim:

Sistema não funciona.

Isso é quase poesia abstrata.

Bug bom:

BUG-5832

Título:
PIX acima de R$5.000 falha após autenticação.

Ambiente:
UAT / Build 2026.09.05

Pré-condição:
Conta ativa com saldo de R$20.000.

Passos:
1. Login
2. PIX
3. Informar R$6.000
4. Confirmar
5. Informar token

Esperado:
Transação aprovada.

Atual:
HTTP 500.

Evidência:
Timestamp 21:43:17
Transaction ID ABC123
Log anexado.

Agora temos material investigativo.


36. Regression Testing — o fantasma dos sistemas antigos

Regression pergunta:

Aquilo que funcionava antes continua funcionando depois da alteração?

Em sistemas legados isso é vital.

Você muda:

3 linhas COBOL

e quebra:

12 rotinas
4 jobs
2 relatórios
1 processo escrito em 1997

Não porque COBOL é ruim.

Porque software grande acumula dependências.


37. Smoke Test — primeiro veja se Oz ainda está respirando

Smoke test é verificação rápida.

aplicação sobe?
login funciona?
Db2 conecta?
transação básica passa?

Se falhar, não execute quatro mil testes.

Você já sabe que a build não está pronta.


38. Sanity Test

Depois de uma alteração pequena, execute testes focados.

Exemplo:

Corrigiu cálculo de juros?

Teste:

  • juros;

  • arredondamento;

  • limites;

  • casos relacionados.

Depois execute regressão adequada.


39. Manual versus Automation

Manual funciona muito bem para:

  • exploração;

  • UX;

  • ad-hoc;

  • cenários novos.

Automação é excelente para:

  • regressão;

  • repetição;

  • API;

  • unit tests;

  • CI/CD.

Mas automatizar tudo não faz sentido.

Se um caso roda uma única vez:

manual = 5 minutos
automação = 4 horas

Talvez não compense.

Se roda mil vezes:

a matemática muda.

Automação é investimento, não religião.


40. Shift Left — encontre o bug antes da Cidade das Esmeraldas

Shift Left significa trazer testing para mais cedo.

Em vez de:

Code
↓
Testing

pensamos:

Requirement
↓
Testing mindset
Design
↓
Testing mindset
Code
↓
Automated tests
Build
↓
Integration tests

O melhor bug é aquele impedido antes de nascer.


41. Shift Right — produção também fala

Depois do deploy, qualidade continua.

Entram:

  • observabilidade;

  • logs;

  • métricas;

  • tracing;

  • synthetic monitoring;

  • canary releases;

  • incident analysis.

Produção não é simplesmente o ponto em que testing termina.

É onde o software encontra o mundo real.

E o mundo real é um tester brutal.


42. Testabilidade — software que esconde erro é inimigo

Imagine dois programas.

Programa A:

ERROR 0001

Programa B:

Transaction ABC123 failed.
Reason: customer status = CLOSED.
Module: PGPIX001.
Timestamp: ...

Qual será mais fácil de investigar?

Testabilidade depende de:

  • logs;

  • mensagens claras;

  • interfaces;

  • observabilidade;

  • controle de dados;

  • isolamento.

Design também influencia testing.


43. Cobertura não é prova de perfeição

Imagine:

COMPUTE TOTAL = VALOR / QUANTIDADE

Você executa essa linha em vários testes.

Cobertura:

100%

Mas nunca testa:

QUANTIDADE = 0

Então:

coverage ≠ correctness

Cobertura informa onde passou.

Não prova que todos os comportamentos importantes foram verificados.


44. O paradoxo final

Testing consegue provar facilmente:

Existe um defeito.

Basta encontrar um.

Mas provar:

Não existe nenhum defeito.

é praticamente impossível em sistemas não triviais.

Há combinações de:

  • dados;

  • estado;

  • concorrência;

  • timing;

  • ambiente;

  • integrações;

  • versões.

Portanto testing trabalha com risco.

A meta não é testar tudo.

É testar as coisas certas com inteligência.


45. Dorothy chega finalmente ao mainframe

Vamos juntar tudo num exemplo.

Requisito:

Permitir aumento do limite diário PIX para R$20.000.

Passo 1 — Requirements

Precisamos esclarecer:

por conta?
por cliente?
dia civil?
inclui agendado?

Passo 2 — Unit

Teste cálculo e validação.

Passo 3 — Equivalence Partitioning

<0
0–20.000
>20.000

Passo 4 — Boundary

-0,01
0
0,01
19.999,99
20.000
20.000,01

Passo 5 — Integration

CICS
COBOL
Db2
MQ
API

Passo 6 — Security

cliente autorizado
cliente bloqueado
conta encerrada
usuário sem permissão

Passo 7 — Performance

10.000 transações/minuto

Passo 8 — Regression

PIX normal
PIX agendado
estorno
comprovante
consulta

Passo 9 — UAT

Negócio confirma comportamento.

Passo 10 — Production

Monitoramos.

Agora sim temos engenharia.


Epílogo — Toto puxa a cortina

Depois de atravessar todo o caminho, Dorothy finalmente encontra o Mágico.

Ela espera aquele ser sobrenatural que garante:

“Software aprovado.”

Toto puxa a cortina.

Atrás dela encontramos:

Requirements
Test Plan
Test Cases
Test Data
Environment
Automation
Execution
Defects
Logs
Metrics
Regression
UAT
Monitoring

Nada de truque.

Nada de fumaça.

Nada de prestidigitação.

A grande revelação é justamente esta:

qualidade não é algo adicionado ao software no fim.

Qualidade começa quando alguém pergunta:

“O que exatamente esse requisito quer dizer?”

Continua quando o programador pergunta:

“O que acontece nos limites?”

Amadurece quando o tester pergunta:

“Como faço isso falhar?”

E chega ao nível profissional quando toda a equipe pergunta:

“Como podemos construir algo que seja verificável, observável, seguro e resistente a mudanças?”

O Espantalho queria um cérebro.

No testing ele descobriu análise.

O Homem de Lata queria coração.

Descobriu que alguém precisa se importar com o usuário que encontra o bug.

O Leão queria coragem.

Descobriu que é preciso coragem para colocar 61, NULL, -1, arquivo vazio e concorrência pesada na aplicação que o desenvolvedor jurou estar pronta.

Dorothy queria voltar para casa.

E o programador COBOL iniciante?

Esse descobre algo ainda mais útil:

há muito tempo ele já possuía uma das melhores ferramentas de testing disponíveis — a capacidade de desconfiar do próprio código.

Porque no fim da Estrada de Tijolos Amarelos existe uma placa pregada na porta do CPD:

        NÃO EXISTE
    “FUNCIONA NA MINHA MÁQUINA”

         COMO STATUS
        DE HOMOLOGAÇÃO.

E em letras menores, provavelmente adicionadas por algum sysprog depois de um abend noturno:

Expected Result != Actual Result

      abre chamado.

☕ E se Toto aparecer perto da cortina da produção, talvez seja uma boa ideia verificar a STEPLIB antes de culpar a Bruxa Má do Oeste.

Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...