☕ 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 Test Data. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Test Data. Mostrar todas as mensagens

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.

sexta-feira, 8 de novembro de 2019

🎩 Mandrake e o Grande Espetáculo dos Testes de Software

 

Bellacosa Mainframe e o mago dos Testes de Software

☕ Um Café no Bellacosa Mainframe

🎩 Mandrake e o Grande Espetáculo dos Testes de Software

Manual Testing, STLC, Test Cases, Test Data, defeitos, regressão e a arte de descobrir que o sistema nunca fez exatamente aquilo que jurava fazer

“Senhoras e senhores, observem atentamente. O programa funciona. Agora começa o truque.”

 


Há algo profundamente mágico no desenvolvimento de software.

Um programador recebe requisitos, transforma ideias em código, compila aquilo, executa o programa e, finalmente, a tela responde:

PROCESS COMPLETED SUCCESSFULLY
RETURN CODE = 0000

A plateia aplaude.

O gerente respira aliviado.

O desenvolvedor fecha o notebook.

E, sentado discretamente na primeira fila, Mandrake não aplaude.

Ele observa.

Porque todo mágico conhece uma regra fundamental:

aquilo que você vê não necessariamente corresponde ao que realmente aconteceu.

E talvez essa seja uma das melhores maneiras de compreender Software Testing.

O tester profissional não está tentando provar que o programa funciona.

Está tentando descobrir em quais circunstâncias ele deixa de funcionar.

É aí que começa nosso espetáculo.



🎩 ATO I — O programa que jurava estar funcionando

Imagine um pequeno programa COBOL:

IF SALDO >= VALOR-COMPRA
    SUBTRACT VALOR-COMPRA FROM SALDO
    MOVE 'APROVADA' TO STATUS-COMPRA
ELSE
    MOVE 'NEGADA' TO STATUS-COMPRA
END-IF.

Executamos:

SALDO        = 1000
VALOR-COMPRA = 100

Resultado:

STATUS = APROVADA
SALDO  = 900

Fantástico.

O programa funciona!

Mandrake levanta uma sobrancelha.

— Funciona?

Experimentemos então:

SALDO = 1000
VALOR-COMPRA = 1000

Funciona.

Agora:

SALDO = 1000
VALOR-COMPRA = 1001

Negada.

Muito bem.

Mas Mandrake continua:

VALOR-COMPRA = 0

Depois:

VALOR-COMPRA = -100

Depois:

VALOR-COMPRA = 999999999999999

Depois uma transação duplicada.

Depois duas transações simultâneas.

Depois Db2 indisponível.

Depois MQ demora 30 segundos para responder.

Depois o programa sofre ABEND entre o débito e o COMMIT.

Depois o mesmo arquivo é submetido novamente pelo scheduler.

De repente, aquele simples:

IF SALDO >= VALOR-COMPRA

transformou-se numa investigação.

Bem-vindo ao teste de software.

O próprio currículo atual do ISTQB coloca os fundamentos, testes ao longo do ciclo de desenvolvimento, testes estáticos, técnicas de teste, gerenciamento de riscos, defeitos e ferramentas dentro da formação básica do profissional. Ou seja: testar está muito além de simplesmente executar uma tela e verificar se apareceu a mensagem correta. (ISTQB)



🪄 ATO II — QA, QC e Testing: três truques diferentes

Nas anotações que analisamos aparecem três conceitos importantes:

Quality Assurance, Quality Control e Testing.

Podemos imaginá-los no teatro de Mandrake.

QA — Quality Assurance tenta impedir que o truque seja preparado de maneira errada.

Pergunta:

Nosso processo permite produzir software de qualidade?

QA olha para padrões, processos, revisões, métodos, critérios e prevenção.

QC — Quality Control examina aquilo que foi produzido.

Pergunta:

Este produto possui a qualidade esperada?

E finalmente temos Testing.

O tester coloca o produto diante dele e pergunta:

O que acontece se eu fizer isto?

E então começa a puxar as cortinas.

Mas há uma sutileza importante: testing não significa apenas executar programas. O processo moderno também inclui testes estáticos, como revisão de requisitos, documentação, código e outros artefatos antes mesmo da execução do software. Isso aparece explicitamente no CTFL atual. (ISTQB)

Essa é uma das grandes mágicas econômicas da engenharia de software:

encontrar um problema antes de ele virar código.



🔮 ATO III — Error → Defect → Failure

Mandrake coloca três cartas sobre a mesa:

ERROR
DEFECT
FAILURE

Parecem semelhantes.

Não são.

Imagine que alguém escreve um requisito:

Clientes com saldo >= valor da compra
podem realizar a transação.

O programador interpreta errado e escreve:

IF SALDO > VALOR-COMPRA

em vez de:

IF SALDO >= VALOR-COMPRA

O engano humano está na origem.

Esse engano produz um defeito no software.

Quando alguém possui:

SALDO = 100
COMPRA = 100

e o sistema responde:

TRANSACTION DECLINED

temos a manifestação observável do problema: uma falha.

Portanto, conceitualmente podemos imaginar:

ERRO HUMANO
     ↓
DEFEITO INTRODUZIDO
     ↓
CONDIÇÃO ESPECÍFICA
     ↓
EXECUÇÃO
     ↓
FALHA OBSERVÁVEL

E aqui existe um princípio precioso.

Um defeito pode permanecer escondido durante anos.

Ele somente aparece quando determinadas condições o ativam.

O código pode ter sido executado milhões de vezes sem problema.

Até que chega:

29/02

ou:

31/12 23:59:59

ou um campo com valor máximo.

Ou um registro duplicado.

Ou alguém finalmente passa pelo caminho lógico esquecido.

O coelho sempre esteve dentro da cartola.

Apenas ninguém havia olhado direito.



🎭 ATO IV — SDLC: preparando o palco

Antes do espetáculo existe toda uma produção.

No desenvolvimento clássico temos algo semelhante a:

REQUISITOS
    ↓
DESIGN
    ↓
DESENVOLVIMENTO
    ↓
TESTES
    ↓
DEPLOYMENT
    ↓
MANUTENÇÃO

Isso é uma representação simplificada do Software Development Life Cycle — SDLC.

Mas cuidado com uma ilusão muito comum:

CODING → TESTING

pode sugerir que testing começa depois da programação.

Em engenharia moderna isso é uma simplificação perigosa.

Testes podem começar no requisito.

Mandrake recebe:

“O sistema deverá responder rapidamente.”

Ele imediatamente pergunta:

Quanto é rapidamente?

200 milissegundos?

Dois segundos?

Dez?

Sob qual volume?

Com quantos usuários?

Em qual infraestrutura?

Perceba o truque.

Acabamos de testar um requisito sem executar uma única linha de código.

Essa integração entre testing e diferentes modelos de desenvolvimento é justamente parte da abordagem atual do CTFL, que considera Waterfall, Agile, DevOps e Continuous Delivery. (ISTQB)



🪄 ATO V — Waterfall, V-Model, Iterative, Incremental e Spiral

As anotações apresentam vários modelos.

No Waterfall, as etapas parecem uma escada:

Requirements
      ↓
Design
      ↓
Development
      ↓
Testing
      ↓
Deployment

É fácil de compreender e administrar quando requisitos são relativamente estáveis.

O problema aparece quando descobrimos tarde que o requisito inicial estava errado.

O V-Model melhora a conversa entre desenvolvimento e teste.

De um lado:

Requirements
System Design
Architecture
Coding

Do outro:

Acceptance Testing
System Testing
Integration Testing
Component Testing

A ideia essencial é poderosa:

cada nível de construção deve possuir alguma forma correspondente de verificação ou validação.

Já abordagens iterativas e incrementais quebram a entrega em pedaços menores.

Mandrake prefere pequenos truques verificáveis a esperar dois anos pelo desaparecimento completo do elefante.

E o Spiral Model acrescenta explicitamente algo fundamental:

risco.

Quanto maior o risco, maior deve ser nossa atenção.

Isso nos conduz ao Risk-Based Testing.

Um botão que altera a cor de um avatar e uma rotina que liquida R$ 500 milhões não deveriam receber exatamente a mesma prioridade de testes.

Probabilidade × impacto muda completamente a estratégia.

O gerenciamento de riscos também está explicitamente presente no currículo contemporâneo do ISTQB. (ISTQB)


🎩 ATO VI — STLC: o espetáculo dentro do espetáculo

Se SDLC organiza o desenvolvimento, o Software Testing Life Cycle organiza o trabalho de testing.

Uma representação didática é:

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

Mas não devemos imaginar isso obrigatoriamente como uma ferrovia em que o trem nunca volta.

Na prática:

Requirement
     ↓
Test
     ↓
Defect
     ↓
Requirement reconsidered
     ↓
Code changed
     ↓
New test
     ↓
Regression

O próprio ISTQB observa que os níveis de teste podem se sobrepor temporalmente em modelos iterativos. (ISTQB)

Testing é muito mais uma espiral de descoberta do que uma simples linha reta.


🃏 ATO VII — Os níveis do teste

Nas anotações encontramos:

Unit
Integration
System
Acceptance

Excelente modelo mental inicial.

Mas aqui Mandrake tira outra carta da manga.

O CTFL atual descreve formalmente cinco níveis:

Component
Component Integration
System
System Integration
Acceptance

(ISTQB)

Isso é particularmente interessante para quem trabalha com mainframe.

Imagine:

COBOL PROGRAM
     ↓
Db2
     ↓
CICS
     ↓
MQ
     ↓
z/OS Connect
     ↓
API
     ↓
Mobile App

Testar apenas o COBOL não testa o sistema.

Talvez o COBOL esteja perfeito.

Talvez a API esteja perfeita.

Mas:

API JSON
   ↓
z/OS Connect
   ↓
COMMAREA

pode estar convertendo incorretamente:

100.50

para:

10050

Cada componente funciona.

A integração está errada.

Esse é um dos defeitos mais traiçoeiros da computação.

Todos os mágicos fizeram seus truques corretamente.

Mas o espetáculo fracassou.


🪄 ATO VIII — Functional e Non-Functional Testing

Agora Mandrake coloca duas caixas no palco.

Na primeira:

O QUE O SISTEMA FAZ?

Na segunda:

COMO O SISTEMA FAZ?

A primeira nos conduz ao Functional Testing.

Exemplo:

COMPRA = R$ 100
LIMITE = R$ 500

Esperado:

APROVADA

Estamos verificando uma regra funcional.

Mas suponha que a autorização leve:

37 segundos

Funcionalmente está correta.

Operacionalmente talvez seja desastrosa.

Entramos então no Non-Functional Testing:

performance, segurança, usabilidade, confiabilidade, escalabilidade, compatibilidade, acessibilidade e outras características de qualidade.

O CTFL atual trata tipos de teste como grupos de atividades ligados a características específicas e observa que eles podem aparecer em diferentes níveis de teste. (ISTQB)

Ou seja:

nível e tipo são dimensões diferentes.

Essa distinção vale ouro.


🧙 ATO IX — Black Box: Mandrake não quer saber como funciona

Temos uma máquina.

Entrada:

AGE = 30

Saída:

ACCEPTED

Mandrake não vê o código.

Ele conhece apenas a especificação:

18 <= AGE <= 60

Podemos então usar Equivalence Partitioning.

Em vez de testar todos os números possíveis, dividimos o universo:

< 18       INVALID
18..60     VALID
> 60       INVALID

Selecionamos representantes:

10
30
70

Três testes cobrem conceitualmente três classes.

É uma maneira elegante de reduzir uma quantidade praticamente infinita de possibilidades.


🎩 ATO X — Boundary Value Analysis: o mágico encontra um erro nas próprias anotações

E aqui acontece algo maravilhoso.

Temos:

IDADE PERMITIDA = 18 até 60

Uma análise de fronteira típica poderia testar:

17
18
19
59
60
61

Porque bugs adoram morar nas fronteiras:

<
<=
>
>=

Mas uma das imagens das nossas próprias anotações apresenta a sequência:

17  18  19  60  61

e ainda associa incorretamente os rótulos próximos ao máximo.

🎩 ABRACADABRA!

Encontramos um defeito num material que ensina como encontrar defeitos.

Esse será nosso Easter Egg.

🐇 Easter Egg Bellacosa #03:17: o primeiro bug do curso estava escondido justamente no capítulo sobre Boundary Value Analysis.

Não poderia existir demonstração melhor.

O tester precisa testar até mesmo aquilo que lhe ensina a testar.


🃏 ATO XI — Decision Table

Agora imagine autorização de cartão:

Cartão ativo?
Senha correta?
Limite disponível?
Suspeita de fraude?

Temos combinações.

AtivoSenhaLimiteFraudeResultado
SSSNAprovar
NSSNNegar
SNSNNegar
SSNNNegar
SSSSRevisar/Negar

Isso é perfeito para Decision Table Testing.

Em COBOL poderíamos encontrar:

EVALUATE TRUE
    WHEN CARTAO-BLOQUEADO
         PERFORM NEGAR-COMPRA

    WHEN SENHA-INVALIDA
         PERFORM NEGAR-COMPRA

    WHEN SEM-LIMITE
         PERFORM NEGAR-COMPRA

    WHEN SUSPEITA-FRAUDE
         PERFORM ANALISAR-COMPRA

    WHEN OTHER
         PERFORM APROVAR-COMPRA
END-EVALUATE.

Cada WHEN é praticamente Mandrake dizendo:

“Mostre-me sua próxima carta.”


🔮 ATO XII — State Transition

Existem sistemas nos quais o resultado depende não apenas da entrada atual, mas do estado anterior.

Cartão:

ACTIVE
  ↓
3 senhas erradas
  ↓
BLOCKED

Agora tente a senha correta.

O sistema deveria desbloquear automaticamente?

Provavelmente não.

Então temos:

STATE + EVENT → NEW STATE

Isso é State Transition Testing.

Em mainframe isso aparece por toda parte:

NEW
AUTHORIZED
CAPTURED
SETTLED
REVERSED
CANCELLED

Uma transação SETTLED talvez não possa simplesmente voltar para NEW.

O tester procura transições permitidas e, principalmente, transições proibidas.


🪄 ATO XIII — Error Guessing: a experiência entra no palco

Depois de alguns anos trabalhando com sistemas, desenvolvemos algo curioso.

Vemos:

PIC 9(5)

e imediatamente pensamos:

99999?
00000?
SPACE?
-1?
100000?

Vemos:

DIVIDE A BY B

e pensamos:

B = ZERO?

Vemos:

SQL INSERT

e pensamos:

DUPLICATE KEY?

Vemos arquivo batch:

INPUT-FILE

e perguntamos:

arquivo vazio?
registro truncado?
layout errado?
duplicado?
EBCDIC/ASCII?
campo COMP-3 inválido?

Isso é experiência transformada em técnica.

É o velho programador olhando para a cartola e dizendo:

“Eu conheço esse truque.”


🎭 ATO XIV — O Test Case

Um bom test case deveria permitir que outra pessoa reproduzisse nossa experiência.

Por exemplo:

TC-CARD-017

Objetivo:
Validar compra exatamente no limite disponível.

Precondition:
Cartão ACTIVE
Limite disponível = R$ 1.000

Input:
Compra = R$ 1.000

Expected:
Authorization = APPROVED
Available Limit = R$ 0
Transaction recorded once

Actual:
...

Status:
PASS / FAIL

Repare no detalhe:

Não basta escrever:

Expected = SUCCESS

Precisamos saber o que significa sucesso.

Esse é o conceito do test oracle: de onde vem nossa certeza sobre o resultado esperado?

Pode ser uma regra de negócio, requisito, cálculo independente, especificação, sistema anterior ou conhecimento validado do domínio.

Porque existe uma situação deliciosamente cruel:

o software pode produzir exatamente o resultado descrito no test case e ambos estarem errados.


🧪 ATO XV — Test Data: os objetos escondidos na manga

Um teste maravilhoso com dados ruins continua sendo um teste ruim.

Para idade 18–60 podemos preparar:

VALID
25
30
45

INVALID
-5
70
ABC

BOUNDARY
17
18
19
59
60
61

No mainframe a brincadeira fica muito mais interessante.

Imagine:

05 WS-AMOUNT PIC S9(9)V99 COMP-3.

Mandrake começa imediatamente a imaginar:

ZERO
NEGATIVO
MÁXIMO
CENTAVOS
SINAL INVÁLIDO
PACKED DECIMAL CORROMPIDO
CAMPO TRUNCADO

E alguém na plateia grita:

S0C7!

Exatamente.

Agora estamos conversando.


🏰 ATO XVI — Test Environment

Um teste não acontece no vazio.

Temos:

DEV
 ↓
QA
 ↓
STAGING
 ↓
PRODUCTION

Mas “funcionou em QA” não significa necessariamente:

funcionará em PROD

Talvez QA tenha:

1.000 registros

e produção:

800 milhões.

Talvez QA tenha uma LPAR praticamente ociosa.

Produção possui WLM disputando recursos.

Talvez QA utilize outra configuração de Db2.

Outro RACF.

Outra versão de copybook.

Outra configuração MQ.

Outro timeout.

Outra quantidade de initiators.

Outra definição CICS.

Esse fenômeno possui um inimigo conhecido:

environment drift.

Quanto maior a diferença entre os ambientes relevantes, maior a possibilidade de o teste produzir confiança falsa.


🐇 ATO XVII — Defect Management

Finalmente Mandrake captura o coelho.

Agora precisamos documentá-lo.

Um fluxo possível:

NEW
 ↓
ASSIGNED
 ↓
OPEN
 ↓
IN PROGRESS
 ↓
FIXED
 ↓
RETEST
 ↓
VERIFIED
 ↓
CLOSED

Se ainda falhar:

REOPEN

Mas isso não é uma lei universal.

Cada organização pode possuir seu próprio workflow.

O mesmo vale para:

P0
P1
P2
P3

Aliás, as próprias anotações analisadas usam convenções diferentes em páginas distintas: numa delas P1 aparece como crítico; em outra, P0 é crítico.

Outro pequeno coelho escondido.

Isso demonstra algo importante:

Priority é convenção organizacional.

Já a distinção conceitual é mais importante:

SEVERITY
= qual o impacto do defeito?

PRIORITY
= quão urgentemente queremos resolvê-lo?

Um erro ortográfico na página inicial de um grande banco pode ter baixa severidade técnica e prioridade altíssima.

Um defeito grave em funcionalidade raramente utilizada pode possuir severidade alta e prioridade temporariamente menor.


🔁 ATO XVIII — Retest não é Regression

Mandrake quebra uma carta.

O desenvolvedor cola.

Mandrake verifica a carta.

Isso é confirmation/retest:

O defeito específico foi corrigido?

Mas Mandrake pergunta:

E ao colar esta carta você rasgou outra?

Isso é regression testing.

O currículo atual do ISTQB trata confirmation testing e regression testing como conceitos distintos justamente por essa razão. (ISTQB)

Imagine:

BUG:
cálculo de juros incorreto.

Correção realizada.

Retest:

juros agora corretos.

Excelente.

Regression:

parcelamento?
estorno?
fatura?
pagamento mínimo?
limite?
contabilidade?
extrato?

O bug morreu.

Agora precisamos descobrir se ele levou algum vizinho junto.


🖥️ ATO XIX — Mandrake entra numa LPAR

E aqui nosso espetáculo chega ao território Bellacosa Mainframe.

Mandrake encontra:

JCL
 ↓
COBOL
 ↓
VSAM
 ↓
Db2
 ↓
CICS
 ↓
MQ
 ↓
APIs

E percebe imediatamente que o RC=0000 é apenas o começo.

Um tester de mainframe deveria aprender a procurar evidências em coisas como:

RETURN-CODE
SQLCODE
CICS RESP
RESP2
ABEND CODE
JESMSGLG
JESJCL
JESYSMSG
SYSOUT
CEEDUMP

Imagine um JOB:

STEP01 → SORT
STEP02 → COBOL
STEP03 → Db2
STEP04 → REPORT

O JOB termina:

MAXCC=0000

Tudo certo?

Mandrake responde:

Quantos registros entraram?

1.000.000

Quantos foram processados?

999.998

Quantos foram rejeitados?

0

Então onde estão dois registros?

🎩 Eis o truque.


🧮 ATO XX — Reconciliation: a mágica que salva dinheiro

Em sistemas financeiros existe uma forma particularmente poderosa de testing:

reconciliação.

Podemos estabelecer invariantes:

INPUT =
PROCESSED +
REJECTED

ou:

SALDO ANTERIOR
+ CRÉDITOS
- DÉBITOS
= SALDO FINAL

Agora imagine:

INPUT      = 10.000
PROCESSED  = 9.997
REJECTED   = 2

Temos:

10.000 ≠ 9.997 + 2

Um registro desapareceu.

Não sabemos ainda onde.

Mas sabemos que há alguma coisa atrás da cortina.

Isso é extraordinariamente importante em cartões, pagamentos, bancos, seguros e processamento batch.

O resultado bonito na tela não basta.

Precisamos provar que os números fecham.


💥 ATO XXI — O teste favorito de Mandrake: quebrar no meio

Agora imagine processamento:

READ TRANSACTION
      ↓
UPDATE ACCOUNT
      ↓
WRITE HISTORY
      ↓
SEND MQ
      ↓
COMMIT

Mandrake desliga alguma coisa exatamente aqui:

UPDATE ACCOUNT
      ↓
       💥

E pergunta:

O que acontece agora?

Rollback?

Commit parcial?

Registro inconsistente?

Mensagem perdida?

Duplicação durante restart?

É aqui que testing deixa de ser simplesmente “clicar na tela”.

Em sistemas críticos precisamos testar:

RESTART
RECOVERY
ROLLBACK
REPROCESSING
DUPLICATE DELIVERY
TIMEOUT
DEADLOCK
PARTIAL FAILURE

Porque produção possui um talento extraordinário para criar condições que ninguém imaginou durante a happy path.


🧙‍♂️ ATO XXII — O S0C7 escondido na cartola

Considere:

05 WS-AMOUNT PIC S9(7)V99 COMP-3.

Tudo funciona durante meses.

Até chegar um registro corrompido.

O programa tenta executar uma operação aritmética.

💥

S0C7

O defeito talvez não esteja exatamente na instrução que sofreu o ABEND.

Pode ter começado muito antes:

arquivo
 ↓
layout incorreto
 ↓
campo deslocado
 ↓
dados inválidos
 ↓
operação decimal
 ↓
S0C7

O tester não pode perguntar apenas:

Onde explodiu?

Precisa perguntar:

Onde começou a cadeia causal que permitiu a explosão?

Isso é pensamento investigativo.


🔐 ATO XXIII — Segurança também faz parte do espetáculo

Suponha:

USER = VAGNER
ROLE = VIEWER

Ele deveria consultar relatório.

Mas consegue alterar registros.

Funcionalmente o botão funciona perfeitamente.

O problema é justamente esse.

Ele não deveria funcionar para aquele usuário.

Portanto testamos:

AUTHENTICATION
       ↓
Quem é você?

AUTHORIZATION
       ↓
O que você pode fazer?

No mundo mainframe isso imediatamente lembra RACF e os controles existentes ao redor de datasets, transações, recursos e identidades.

O verdadeiro teste negativo seria:

Mostre que Vagner consegue acessar aquilo que deve acessar.

e também:

Mostre que Vagner não consegue acessar aquilo que não deve acessar.

A segunda parte frequentemente é mais valiosa.


🤖 ATO XXIV — Manual Testing versus Automation

E chegamos à falsa guerra:

MANUAL
   VS
AUTOMATION

Não existe necessidade dessa guerra.

Automação é fantástica para:

regressão repetitiva
grandes massas
execuções frequentes
CI/CD
comparações
APIs
checks determinísticos

O ser humano continua excelente em:

exploração
investigação
ambiguidade
usabilidade
novos comportamentos
descoberta

A automação executa rapidamente aquilo que alguém ensinou a procurar.

O tester humano pode perguntar:

E se fizermos algo que ninguém colocou no script?

Essa pergunta continua perigosíssima.

O próprio CTFL inclui benefícios e riscos da automação como parte da formação fundamental, em vez de tratá-la como substituta universal do testing humano. (ISTQB)


🔍 ATO XXV — Exploratory Testing: Mandrake abandona o roteiro

Existe ainda uma atividade que merece espaço especial.

Mandrake recebe o sistema sem um roteiro de cinquenta páginas.

Ele começa a explorá-lo.

Aprende enquanto testa.

Testa enquanto aprende.

Observa uma resposta estranha.

Segue aquela pista.

Encontra outra.

Isso é a essência do exploratory testing.

Não significa sair clicando aleatoriamente.

Um bom explorador possui objetivo, conhecimento, heurísticas, observação e documentação.

É jazz.

Não ausência de música.


📊 ATO XXVI — “97% dos testes passaram!”

Mandrake olha para o dashboard:

10.000 TEST CASES

PASS = 9.700
FAIL = 300

PASS RATE = 97%

O gerente comemora.

Mandrake pergunta:

Quais foram os 300 que falharam?

Resposta:

Transferência bancária
Autorização
Liquidação
Recovery
Login administrativo

Então os 97% significam quase nada.

Métricas sem contexto também fazem ilusionismo.

Podemos possuir:

99,9% PASS

e ainda assim ter um sistema impossível de colocar em produção.

Por isso testing baseado em risco é tão importante.

Não contamos apenas testes.

Precisamos saber o que eles protegem.


🎩 ATO XXVII — O verdadeiro Testing Pyramid

A famosa pirâmide costuma aparecer assim:

           /\
          /UI\
         /----\
        / API  \
       /--------\
      / UNIT     \
     /____________\

Muitos testes pequenos e baratos próximos aos componentes.

Menos testes grandes e caros no topo.

É uma heurística útil.

Não uma lei da física.

Em mainframe talvez nossa realidade tenha:

UNIT / COMPONENT
       ↓
BATCH PROGRAM
       ↓
DB2 / VSAM
       ↓
CICS / MQ
       ↓
SYSTEM INTEGRATION
       ↓
END-TO-END

A arquitetura deveria orientar a estratégia.

Não um desenho bonito encontrado num PowerPoint.


🕯️ ATO XXVIII — Shift Left e Shift Right

Mandrake agora realiza seu último truque.

Move testing para a esquerda:

REQUIREMENT
DESIGN
CODE
BUILD
TEST
DEPLOY

Shift Left significa encontrar problemas mais cedo.

Revisar requisitos.

Testar regras.

Executar análise estática.

Criar testes junto com desenvolvimento.

Mas Mandrake também olha para a direita.

Depois do deployment podemos aprender com:

monitoring
telemetry
synthetic transactions
canary releases
observability
production feedback

Isso é parte da mentalidade de Shift Right.

Não significa transformar produção num laboratório irresponsável.

Significa reconhecer uma realidade:

nenhum ambiente reproduz completamente o mundo real.


🧠 ATO FINAL — O tester não caça bugs; caça confiança falsa

Depois de tudo isso, podemos resumir o aprendizado das anotações numa transformação mental.

O iniciante olha para:

INPUT → PROGRAM → OUTPUT

O tester começa a enxergar:

                 REQUIREMENT
                     ↓
INPUT → VALIDATION → BUSINESS RULE
                     ↓
                   DATA
                     ↓
                INTEGRATION
                     ↓
                 OUTPUT
                     ↓
              SIDE EFFECTS
                     ↓
              AUDIT / LOG
                     ↓
                RECOVERY

E pergunta:

O requisito está certo?

O dado está certo?

A fronteira está certa?

A regra está certa?

O resultado está certo?

O banco foi atualizado?

A mensagem foi enviada?

A mensagem foi enviada uma vez?

O rollback funciona?

O restart duplica alguma coisa?

O usuário possui autorização?

A evidência é suficiente?

Outro componente foi quebrado?

O que acontece sob carga?

O que acontece quando algo falha?

Esse é o momento em que Manual Testing deixa de ser uma coleção de definições e passa a ser engenharia.

O ISTQB moderno reforça exatamente essa amplitude: testing dentro do ciclo de desenvolvimento, técnicas black-box, white-box e baseadas em experiência, testes estáticos, risco, defeitos e automação fazem parte de um mesmo corpo de conhecimento. (ISTQB)

Mandrake finalmente fecha a cartola.

O gerente pergunta:

— Então conseguimos provar que o sistema não possui bugs?

Mandrake sorri.

Não.

Mas conseguimos algo muito mais útil.

Descobrimos onde procurá-los, quais riscos realmente importam, quais evidências sustentam nossa confiança e, principalmente, aprendemos a nunca confundir:

RC=0000

com:

TUDO ESTÁ CERTO.

Porque no mainframe, como num espetáculo de mágica, o perigo não está necessariamente naquilo que vemos acontecer.

Está também naquilo que aconteceu atrás da cortina enquanto todos estavam olhando para outro lado.

E às 03:17, quando aquele JOB que funcionou perfeitamente durante 4.327 execuções finalmente encontrar o registro que ninguém imaginou testar...

...talvez algum velho tester sorria diante do SYSOUT e diga:

“Eu sabia que havia um coelho nessa cartola.” 🎩🐇

ISTQB Certified Tester Foundation Level 4.0


segunda-feira, 7 de outubro de 2019

🕯️ John Constantine e a API dos Condenados Requests, Responses, HTTP, JSON, autenticação, autorização, Test Data, ambientes, segurança, automação e aquele 200 OK

 

Bellacosa Mainframe e as APIs

☕ Um Café no Bellacosa Mainframe

🕯️ John Constantine e a API dos Condenados

Requests, Responses, HTTP, JSON, autenticação, autorização, Test Data, ambientes, segurança, automação e aquele 200 OK que jurava que estava tudo bem

Há uma regra que aprendi depois de muitos anos diante de terminais verdes, JCLs, CICS, dumps, arquivos VSAM e bancos de dados:

quando um sistema diz que está tudo bem depressa demais, comece a desconfiar.

John Constantine provavelmente concordaria.

Constantine não é exatamente o sujeito que você chama quando a torneira está vazando. Ele aparece quando a torneira começa a falar latim, o encanador desaparece e alguém encontra um pentagrama desenhado atrás da caixa-d'água.

Com APIs acontece algo semelhante.

Você manda:

GET /customers/42

e recebe:

HTTP/1.1 200 OK

O programador iniciante sorri.

Constantine acende um cigarro imaginário, olha para o monitor e pergunta:

— OK para quem?

Essa é a pergunta que guiará nossa investigação.

Porque uma API pode responder 200 OK enquanto devolve os dados errados. Pode autenticar João e entregar os registros de Maria. Pode registrar uma compra duas vezes. Pode diminuir o estoque três vezes. Pode devolver um CPF que jamais deveria estar naquela resposta.

E existe algo ainda mais diabólico.

Às vezes o sistema está certo...

...e o teste é que está errado.

Bem-vindo ao submundo de API Testing.



🕯️ CAPÍTULO 1 — O que diabos é uma API?

API significa:

Application Programming Interface.

Uma definição simples seria:

uma interface que permite que dois componentes de software se comuniquem seguindo regras previamente estabelecidas.

O exemplo clássico é o restaurante.

Temos:

CLIENTE
   ↓
GARÇOM
   ↓
COZINHA

O cliente não entra na cozinha para preparar o prato.

Ele faz um pedido.

O garçom leva esse pedido à cozinha.

A cozinha trabalha.

O garçom retorna com o resultado.

No mundo computacional:

APLICAÇÃO
    ↓
   API
    ↓
SERVIDOR

Uma aplicação meteorológica poderia solicitar:

GET /weather?city=Itatiba

e receber:

{
  "temp": 28,
  "condition": "Cloudy"
}

A aplicação não precisa saber como o servidor calculou aquilo.

Pode haver Python lá atrás.

Java.

Node.js.

Ou algo bem mais interessante para nós:

APP
 │
 ▼
REST API
 │
 ▼
API Gateway
 │
 ▼
z/OS Connect
 │
 ▼
CICS
 │
 ▼
COBOL
 │
 ├── Db2
 ├── VSAM
 ├── IMS
 └── MQ

Para quem chamou a API, isso deveria ser transparente.

Esse é o primeiro princípio importante:

a API oferece um contrato, não uma visita guiada à implementação.



🔮 CAPÍTULO 2 — O contrato

Constantine conhece contratos.

Normalmente os dele envolvem demônios, almas e cláusulas que ninguém deveria assinar sem ler as letras pequenas.

APIs também possuem contratos.

Se estabelecemos:

GET /users/42

podemos definir que a resposta bem-sucedida será:

200 OK
Content-Type: application/json

com:

{
  "id": 42,
  "name": "Asha",
  "active": true
}

Isso estabelece expectativas.

id deve existir.

id deve ser numérico.

name deve ser texto.

active deve ser booleano.

Portanto:

"id": 42

e:

"id": "42"

não são necessariamente equivalentes.

Um frontend permissivo talvez converta silenciosamente um para o outro.

O contrato não deveria depender dessa benevolência.

É justamente aí que entram schemas e especificações como OpenAPI: eles tornam parte dessas expectativas formalmente verificáveis.



🩸 CAPÍTULO 3 — Request e Response

Toda invocação começa com um pedido.

Por exemplo:

POST /users
Content-Type: application/json

Body:

{
  "name": "Asha",
  "role": "Tester"
}

O servidor poderia responder:

201 Created

e:

{
  "id": 42,
  "name": "Asha",
  "role": "Tester"
}

Temos então:

REQUEST
   ↓
API
   ↓
PROCESSAMENTO
   ↓
RESPONSE

O REQUEST é a pergunta.

O RESPONSE é a resposta.

Mas o investigador competente guarda ambos quando alguma coisa dá errado.

Porque perguntar:

"Por que a API falhou?"

sem saber exatamente qual request foi enviado é quase tão produtivo quanto perguntar a Constantine:

"Alguma coisa sobrenatural aconteceu ontem. Descubra."



🪦 CAPÍTULO 4 — Os cinco rituais HTTP

Os métodos mais comuns são:

GET     → consultar
POST    → criar/processar
PUT     → substituir
PATCH   → alterar parcialmente
DELETE  → remover

Uma sequência CRUD poderia ser:

POST   /users
GET    /users/42
PATCH  /users/42
DELETE /users/42

Mas cuidado com uma simplificação comum.

HTTP não é CRUD.

Podemos perfeitamente encontrar:

POST /payments/123/capture

Nesse caso não estamos simplesmente dizendo "CREATE".

Estamos solicitando uma operação de negócio.

Existem ainda métodos como HEAD e OPTIONS, e os métodos permitidos também fazem parte da superfície que merece testes de segurança. A OWASP recomenda verificar métodos HTTP disponíveis e controles de acesso associados, inclusive tentando operações com métodos alternativos quando apropriado.



🚪 CAPÍTULO 5 — URL: o endereço da casa assombrada

Considere:

https://api.shop.com/v1/products/42?currency=BRL

Podemos desmontá-la:

https://api.shop.com
        │
        └── Base URL

/v1/products/42
        │
        └── endpoint/recurso

42
│
└── path parameter

currency=BRL
│
└── query parameter

E imediatamente surgem testes.

Produto existente:

42

Produto inexistente:

999999999

Valor estranho:

-1

Moeda válida:

BRL

Moeda inválida:

MORDOR

Campo ausente.

Campo vazio.

Valor enorme.

Caracteres especiais.

É aqui que o QA começa a se comportar como Constantine:

não pergunta somente o que deveria funcionar; pergunta também o que acontece quando alguém faz aquilo que não deveria.


🔑 CAPÍTULO 6 — Headers: símbolos desenhados na porta

Uma requisição pode carregar informações adicionais:

Content-Type: application/json
Accept: application/json
Authorization: Bearer eyJ...
X-Request-ID: abc-123

Cada header possui uma função.

Content-Type informa o formato enviado.

Accept pode expressar o formato desejado.

Authorization transporta informações necessárias à autenticação/autorização conforme o mecanismo adotado.

E X-Request-ID, ou outro correlation ID equivalente, pode ser extremamente útil.

Imagine:

Browser
   ↓ abc-123
API Gateway
   ↓ abc-123
z/OS Connect
   ↓ abc-123
CICS
   ↓ abc-123
COBOL
   ↓ abc-123
MQ

Quando tudo explode às 03:17, você procura:

abc-123

e consegue reconstruir a passagem daquela transação pelos diversos componentes.

Nos sistemas distribuídos, correlação é praticamente trabalho de detetive.


👹 CAPÍTULO 7 — Os números da besta... HTTP

Não é exatamente 666.

Temos famílias:

1xx → informacional
2xx → sucesso
3xx → redirecionamento
4xx → problema relacionado à requisição/cliente
5xx → falha do lado servidor

Alguns velhos conhecidos:

200 OK
201 Created
204 No Content
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
409 Conflict
429 Too Many Requests
500 Internal Server Error
503 Service Unavailable

Mas existe uma distinção especialmente importante:

401 ≠ 403

Simplificando:

401 — você não está adequadamente autenticado.

403 — sabemos quem você é, mas você não pode fazer aquilo.

É a diferença entre Constantine chegar à porta sem a chave e chegar com a chave correta de uma sala para a qual ele continua não tendo autorização.


🧿 CAPÍTULO 8 — Authentication não é Authorization

Temos duas perguntas:

AUTHENTICATION
Quem é você?

AUTHORIZATION
O que você pode fazer?

Considere:

João → autenticado
Maria → autenticada

Isso não significa:

João → pode consultar dados privados de Maria

Teste:

GET /users/43
Authorization: Bearer TOKEN_DO_JOAO

Se 43 pertence a Maria e João não possui autorização para acessar aquele objeto, a aplicação precisa impedir o acesso.

Esse tipo de vulnerabilidade é importante o bastante para aparecer como Broken Object Level Authorization — BOLA no OWASP API Security Top 10.

O teste profissional, portanto, não pergunta apenas:

Tenho token?

Pergunta:

TOKEN A pode acessar RECURSO A?
TOKEN A pode acessar RECURSO B?
TOKEN B pode acessar RECURSO A?

USER pode executar operação ADMIN?
ADMIN pode?

GET é permitido?
DELETE também?
PATCH?

É uma matriz.

ATOR × RECURSO × AÇÃO

A OWASP descreve justamente esse modelo ator–recurso–ação como uma forma útil de representar e automatizar testes de autorização.


🧪 CAPÍTULO 9 — Positive, Negative e Boundary Testing

Suponha:

idade permitida = 18 até 60

Teste positivo:

25 → ACCEPT

Teste negativo:

"CONSTANTINE" → REJECT

Agora vêm os limites:

17
18
60
61

Por quê?

Porque um humilde:

IF WS-AGE > 18

em vez de:

IF WS-AGE >= 18

pode mandar o jovem de exatamente 18 anos diretamente para o purgatório da regra de negócio.

Os bugs adoram morar nas fronteiras.

Isso vale para:

quantidade
tamanho de senha
valor financeiro
número de itens
datas
paginação
strings
limites de crédito

Sempre pergunte:

o que acontece exatamente antes, exatamente no limite e exatamente depois?


🧟 CAPÍTULO 10 — Um erro correto também é PASS

Esta é deliciosa.

Mandamos:

{}

para uma operação que exige email.

Esperamos:

400

ou talvez 422, conforme o contrato adotado.

E algo como:

{
  "code": "EMAIL_REQUIRED",
  "message": "Email is required",
  "field": "email"
}

Se a aplicação rejeitar corretamente a requisição inválida...

o teste passou.

Parece contraditório somente enquanto confundimos:

API retornou erro

com:

TESTE falhou

Um teste negativo pode perfeitamente produzir:

HTTP ERROR + TEST PASS

O que seria ruim?

Enviar uma requisição inválida e receber:

500 Internal Server Error

quando o contrato previa uma rejeição controlada.

Ou pior:

400 Bad Request

mas metade da transação já foi gravada.

Constantine abre o banco de dados.

E encontra o demônio escondido lá.


🏦 CAPÍTULO 11 — COMMIT e ROLLBACK entram no exorcismo

Agora o mainframeiro começa a sorrir.

Imagine:

Criar pedido
   ↓
Debitar limite
   ↓
Diminuir estoque
   ↓
Criar pagamento

A terceira etapa falha.

O que acontece?

Se o sistema deveria tratar tudo como uma unidade lógica de trabalho, talvez esperemos:

ROLLBACK

e não:

pedido criado
limite debitado
estoque inalterado
pagamento inexistente

Esse é o tipo de criatura que aparece quando testamos apenas o status HTTP.

Recebemos:

500

e pensamos:

"Certo, falhou."

Não.

A investigação ainda não terminou.

Precisamos verificar o estado persistente.


💳 CAPÍTULO 12 — O demônio da duplicidade

Nosso BELLACARD recebe:

COMPRA = R$ 100

O cliente chama a API.

Timeout.

Não sabe se a compra aconteceu.

Tenta novamente.

Agora imagine:

REQUEST #1 → R$100
REQUEST #2 → R$100

Resultado:

R$200

Temos um problema gigantesco.

Em sistemas financeiros, retries, idempotência e mecanismos de deduplicação precisam ser considerados seriamente.

O teste não deveria perguntar somente:

A compra funcionou?

Mas:

O que acontece se a mesma operação chegar novamente?

Em determinadas APIs podemos encontrar mecanismos como:

Idempotency-Key: 8d937...

permitindo reconhecer repetições da mesma intenção.

A pergunta Constantine seria:

Quantas vezes o ritual foi executado quando o cliente jurava tê-lo invocado uma vez?


🪜 CAPÍTULO 13 — A escada dos ambientes

Agora chegamos à nova peça do quebra-cabeça:

LOCAL
  ↓
 QA
  ↓
STAGE
  ↓
PRODUCTION-LIKE

Em organizações reais podemos encontrar inúmeras variações:

DEV
INTEGRATION
QA
SIT
UAT
STAGING
PRE-PROD
PROD

Os nomes são menos importantes que o princípio.

Queremos promover software por ambientes controlados até chegarmos à produção.

No mundo mainframe isso não deveria causar nenhum choque.

Temos há décadas coisas como:

CICSD
CICST
CICSQ
CICSP

ou:

DB2D
DB2T
DB2Q
DB2P

e datasets:

BELLACOSA.DEV.CLIENTES
BELLACOSA.QA.CLIENTES
BELLACOSA.PROD.CLIENTES

DevOps não inventou a separação de ambientes.

Só mudou boa parte do vocabulário e das ferramentas.


🧙 CAPÍTULO 14 — BASE_URL: o DDNAME das APIs

Podemos ter:

BASE_URL=https://qa.api.example.com
TOKEN=***
USER_ID=42

e o teste:

await request.get(
    `${BASE_URL}/users/${USER_ID}`
);

Em Stage:

BASE_URL=https://stage.api.example.com

Em QA:

BASE_URL=https://qa.api.example.com

O teste permanece essencialmente igual.

Isso deveria soar familiar ao programador COBOL.

Em vez de amarrar recursos diretamente ao programa, usamos mecanismos externos de configuração.

No JCL:

//CLIENTE DD DSN=BELLACOSA.QA.CLIENTES,DISP=SHR

e posteriormente:

//CLIENTE DD DSN=BELLACOSA.PROD.CLIENTES,DISP=SHR

O programa não precisa ser recompilado porque mudamos de dataset.

O mesmo princípio reaparece no mundo moderno:

separe código de configuração.


☠️ CAPÍTULO 15 — .env não é um círculo mágico

Um arquivo:

.env.qa

pode conter configuração de QA.

Ótimo.

Mas cuidado:

.env ≠ Secret Vault

Colocar:

PASSWORD=123456
TOKEN=abc123

fora do source principal não torna magicamente esses valores seguros.

Segredos exigem tratamento apropriado durante armazenamento, distribuição, utilização, logging e rotação. A OWASP recomenda evitar segredos hardcoded, minimizar sua exposição e usar soluções adequadas de gestão de segredos conforme a arquitetura.

E jamais faça:

console.log(token);

e depois mande o log inteiro para:

CI REPORT
LOG SERVER
EMAIL
SLACK
ARQUIVO

Você acabou de transformar observabilidade em distribuição de credenciais.


👥 CAPÍTULO 16 — O fantasma chamado USER_ID=42

Suponha que todos os testes utilizem:

USER_ID=42

Pipeline A:

altera usuário 42

Pipeline B:

remove usuário 42

Pipeline C:

consulta usuário 42

Agora temos:

A ──┐
B ──┼── USER 42
C ──┘

Resultado?

Caos.

Um teste passa.

Outro falha.

Executamos novamente.

Passa.

Executamos amanhã.

Falha.

Nasceu o:

👻 FLAKY TEST

E então surge a frase mais perigosa do departamento de QA:

"Roda de novo."

Quando a segunda execução passa, todos vão embora.

Pouco a pouco ninguém acredita mais na suíte automatizada.

Isso destrói o valor do CI/CD.


🧬 CAPÍTULO 17 — Dê uma identidade própria para cada criatura

Uma alternativa é gerar dados únicos:

email = bellacosa+timestamp@example.test

ou utilizar:

UUID

Assim:

TEST A → USER A
TEST B → USER B
TEST C → USER C

Em vez de:

TEST A ─┐
TEST B ─┼── USER 42
TEST C ─┘

Isso aumenta isolamento e reduz colisões.

Mas abre outra porta.


🧹 CAPÍTULO 18 — Quem limpa o pentagrama depois?

Imagine 10.000 execuções criando:

USERS
CARTS
ORDERS
PAYMENTS
SESSIONS

Depois de meses:

TEST-0000001
TEST-0000002
TEST-0000003
...
TEST-9827719

QA virou um cemitério.

Por isso:

SETUP
  ↓
CREATE DATA
  ↓
EXECUTE
  ↓
ASSERT
  ↓
CLEANUP

E há um detalhe crítico:

FAIL
 ↓
CLEANUP

também.

Se a limpeza ocorrer somente quando o teste termina normalmente, justamente os testes problemáticos deixarão mais sujeira.

Constantine jamais abandonaria o pentagrama aberto no chão.

O QA também não deveria abandonar seus registros temporários.


🕵️ CAPÍTULO 19 — Nunca use o cadáver verdadeiro

A regra:

Never use real customer data.

merece atenção especial.

Copiar produção indiscriminadamente:

PROD DATABASE
      ↓
     COPY
      ↓
 QA DATABASE

pode transportar:

nomes
documentos
endereços
telefones
emails
informações financeiras
dados pessoais

para um ambiente que talvez possua controles diferentes de produção.

Dependendo da necessidade, estratégias podem envolver dados sintéticos, mascaramento, anonimização ou tokenização, considerando requisitos técnicos e regulatórios aplicáveis.

E há outro teste maravilhoso:

compare aquilo que a interface mostra com aquilo que a API realmente devolve.

A tela mostra:

Nome: João
Cidade: Itatiba

Mas o JSON devolve:

{
  "name": "João",
  "city": "Itatiba",
  "internalSalary": 12345,
  "cpf": "...",
  "internalRiskScore": 972,
  "passwordResetToken": "..."
}

A interface simplesmente ignorou os campos extras.

O atacante não ignora.

A OWASP recomenda examinar respostas brutas procurando informações sensíveis ou dados desnecessariamente expostos.


🔥 CAPÍTULO 20 — Não teste somente o Response

Chegamos à maior armadilha de todas.

O teste faz:

POST /orders

Recebe:

201 Created

e declara:

PASS

Constantine pergunta:

— Cadê o pedido?

Verificamos.

Existe.

— E o total?

Errado.

— E o estoque?

Diminuiu duas vezes.

— E o pagamento?

Foi criado três vezes.

— E o MQ?

Duas mensagens.

— E o banco?

COMMIT realizado.

O nosso glorioso:

201 CREATED

acabou de virar:

FAIL

Por isso um teste robusto pode precisar validar:

STATUS
HEADERS
BODY
SCHEMA
BUSINESS RULE
SIDE EFFECT
PERSISTENCE
SECURITY
PERFORMANCE

Estamos deixando de testar HTTP.

Estamos testando o sistema através do HTTP.

Essa diferença é gigantesca.


⏱️ CAPÍTULO 21 — Performance e o demônio da média

Imagine:

média = 200 ms

Parece excelente.

Só que:

90 usuários → 100 ms
10 usuários → 1.100 ms

A média esconde sofrimento.

Por isso aparecem medidas como:

p50
p95
p99

Se p95 = 800 ms, aproximadamente 95% das observações ficaram nesse valor ou abaixo, segundo a metodologia empregada.

Isso nos ajuda a enxergar a cauda.

Também podemos observar:

throughput
timeouts
error rate
CPU
memory
disk I/O
database locks
connection pools
queues
threads
retries

E retries merecem carinho especial.

Um servidor começa a ficar lento.

Clientes repetem chamadas.

O servidor recebe ainda mais trabalho.

Fica mais lento.

Clientes repetem ainda mais.

Temos:

SLOW
 ↓
RETRY
 ↓
MORE LOAD
 ↓
SLOWER
 ↓
MORE RETRIES
 ↓
☠️

O inferno distribuído encontrou seu próprio mecanismo de escala.


🤖 CAPÍTULO 22 — Automatizando o exorcismo

Podemos começar com algo pequeno em Playwright:

test('create user', async ({ request }) => {

  const response = await request.post('/users', {
    data: {
      name: 'Asha'
    }
  });

  expect(response.status()).toBe(201);

  const body = await response.json();

  expect(body.name).toBe('Asha');
});

Já é melhor do que testar manualmente toda vez.

Mas podemos evoluir:

status
+
headers
+
schema
+
body
+
business rules
+
authorization
+
side effects
+
cleanup

E executar automaticamente:

COMMIT
  ↓
BUILD
  ↓
UNIT TEST
  ↓
DEPLOY QA
  ↓
API TEST
  ↓
CONTRACT TEST
  ↓
AUTHORIZATION TEST
  ↓
INTEGRATION TEST
  ↓
SECURITY TEST
  ↓
REPORT
  ↓
QUALITY GATE

A OWASP também descreve a automação de testes de autorização como útil para detectar regressões durante o desenvolvimento e os releases.


🖥️ CAPÍTULO 23 — Constantine entra na LPAR

Agora traduzimos tudo para a língua ancestral.

APIMainframe — analogia conceitual
Requestentrada da transação
JSONestrutura de dados
Endpointponto de entrada
HTTP Methodoperação solicitada
HTTP Statusretorno técnico
Tokencontexto de segurança
AuthorizationRACF/controle de acesso conceitualmente
Request IDcorrelation ID
Side Effectresultado transacional
DatabaseDb2/IMS/VSAM
QueueMQ
Rollbackdesfazer LUW
Environmentregião/subsistema/configuração
BASE_URLconfiguração externa/endereço do destino
Test Datamassa de testes

Não são equivalências tecnológicas perfeitas.

São pontes mentais.

E elas mostram uma coisa fascinante:

muito daquilo que o mercado chama hoje de arquitetura moderna possui problemas que mainframeiros conhecem há décadas.

Estado.

Concorrência.

Segurança.

Transações.

Auditoria.

Ambientes.

Configuração.

Recuperação.

Integridade.


🕯️ CAPÍTULO 24 — O exorcismo final

Constantine está diante do monitor.

O teste apresenta:

HTTP/1.1 200 OK

Todo mundo comemora.

Ele não.

Primeira pergunta:

O usuário correto recebeu os dados?

Sim.

O schema está correto?

Sim.

A autorização foi verificada?

Sim.

Existe informação sensível extra?

Não.

O banco ficou consistente?

Sim.

A operação aconteceu uma única vez?

Sim.

As mensagens corretas foram produzidas?

Sim.

O tempo ficou dentro do objetivo definido?

Sim.

O teste utilizou dados isolados?

Sim.

O ambiente era realmente QA?

Sim.

Os segredos ficaram protegidos?

Sim.

A massa criada foi limpa?

Sim.

Agora Constantine olha novamente:

200 OK

E finalmente diz:

— Agora talvez esteja OK.


☕ EPÍLOGO — CC 0000 também pode mentir

Aqui está a lição que une o velho mainframe às APIs modernas.

Nós já aprendemos há décadas que:

CC 0000

não significa necessariamente:

NEGÓCIO CORRETO

Um batch COBOL pode terminar lindamente com:

MAXCC=0000

e ter atualizado 50.000 clientes com a tarifa errada.

Tecnicamente terminou.

Funcionalmente foi uma catástrofe.

Da mesma maneira:

HTTP 200 OK

não significa:

TEST PASSED

Nosso verdadeiro ritual é:

REQUEST VÁLIDO
       +
CONTRATO CORRETO
       +
AUTENTICAÇÃO
       +
AUTORIZAÇÃO
       +
DADOS CORRETOS
       +
REGRA DE NEGÓCIO
       +
SIDE EFFECT CORRETO
       +
ESTADO CONSISTENTE
       +
ISOLAMENTO
       +
SEGURANÇA
       +
PERFORMANCE
       +
CLEANUP
       =
       PASS

E existe ainda uma última possibilidade, aquela que faria Constantine sorrir.

O sistema está correto.

O endpoint está correto.

O banco está correto.

A autorização está correta.

O COMMIT está correto.

Mas o pipeline acusa:

FAILED

Porque dois testes resolveram utilizar simultaneamente:

USER_ID=42

Nesse momento o verdadeiro monstro não está na API.

Está na suíte de testes.

E é por isso que o bom investigador nunca pergunta apenas:

“A API falhou?”

Ele pergunta:

“O que exatamente falhou: o request, o contrato, a autenticação, a autorização, a aplicação, a regra de negócio, a persistência, o ambiente, a configuração, a massa de dados... ou o próprio teste?”

Essa é a diferença entre apertar SEND no Postman e realmente compreender API Testing.

Às 03:17, quando o dashboard fica vermelho e alguém aparece no War Room dizendo “mas estava retornando 200!”, talvez seja tarde demais para chamar John Constantine.

Mas ainda dá tempo de chamar um velho programador COBOL.

Ele provavelmente olhará para aquele 200 OK, lembrará de todos os CC 0000 que já viu mentirem durante a carreira e fará a única pergunta que realmente importa:

— Certo. Mas o que foi gravado no banco? ☕🕯️



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...