Ir para o conteúdo

Patterns by language and test level

Esta página lista o que cada scanner da família detecta, organizado de duas formas: por linguagem (um eixo fixo) e por nível de teste (unidade, integração, E2E). As páginas do catálogo trazem as definições completas; aqui está o mapa que liga as duas.

An honest note about level

Unidade, integração e E2E não são uma partição fixa por código. O nível é uma classificação por achado, decidida no J3: o teste exercita a unidade real, um colaborador ou borda de integração, ou o stack E2E completo. O mesmo padrão de false-green lê no nível em que o teste opera. Então a lista abaixo é completa por linguagem (o eixo fixo), e os clusters de nível no fim são os padrões característicos de cada nível, com a ressalva de que a maioria dos códigos pode aparecer em mais de um nível.

The model

Os julgamentos J1-J6 perguntam, em ordem: a assertion roda, o oráculo é independente, exercita a unidade real ou um dublê, verifica o suficiente, está acoplado a internos, passa em isolamento. A skill é o superconjunto dos três scanners estruturais: os códigos estruturais (C* / JS* / R* / PL*) mais os semânticos (S1-S21), que precisam de uma leitura de intenção que um AST não decide.

Python (falsegreen)

O scanner falsegreen emite 67 códigos sobre pytest e unittest. Cada um liga para sua entrada no catálogo.

Code J Conf What it catches
C1 J1 LOW assertion dentro de condicional ou loop que pode nunca rodar
C2 J1 HIGH corpo do teste sem nenhuma assertion
C3 J1 HIGH assert dentro de um try cujo except engole o erro
C4 J1 HIGH função de teste não coletada pelo pytest
C5 J2 HIGH assertion sempre verdadeira
C6 J4 LOW assertion fraca: só checa que algo voltou
C7 J2 HIGH autocomparação: os dois lados são idênticos
C8 J4 LOW igualdade exata de float
C9 J4 LOW pytest.raises amplo demais
CC J1 LOW assert comentado
C13 J4 HIGH assertion de mock escrita errada ou não chamada
C14 J2 LOW golden file gerado a partir da saída real
C16 J6 LOW resultado depende de tempo, aleatoriedade ou sleep não controlados
C17 J1 HIGH pytest.skip() dentro de except amplo
C18 J2 LOW comparação de string/repr
C19 J1 LOW pytest.raises envolve mais de uma chamada
C20 J1 HIGH assertion após return/raise/fail incondicional
C21 J1 LOW toda assertion está dentro de condicional; nenhuma roda incondicionalmente
C22 J1 OFF teste async nunca dá await na unidade sob teste
C23 J6 LOW caminho de arquivo absoluto ou relativo ao home hard-coded
C24 J6 LOW estado mutável a nível de módulo mutado pelo teste
C25 J1 LOW xfail sem strict=True
C27 J1 HIGH try/except/pass em volta da chamada do SUT sem assertion
C28 J4 LOW variável vinculada por pytest.raises nunca lida
C29 J6 LOW os.environ modificado direto no teste
C2b J1 LOW chama código de produção mas não verifica nada
C2c J1 LOW bloco self.subTest(...) vazio
C30 J3 LOW mock HTTP não ativado
C31 J4 LOW resultado de capsys.readouterr() descartado
C32 J1 LOW @pytest.mark.skip sem motivo
C33 J4 LOW métrica de ML calculada mas não asserida
C34 J4 LOW forma de assertion subótima
C35 J6 LOW decorator de retry/flaky
C36 J1 LOW pytest.fail() sem motivo
C37 J2 LOW caso de parametrize duplicado
C38 J1 HIGH dois testes com o mesmo nome
C39 J1 HIGH retorna uma comparação em vez de asserir
C41 J4 LOW assertion sobre um mutator que retorna None
C42 J2 HIGH assertion sobre um generator ou lambda
C43 J1 LOW skip no meio do teste
C44 J2 HIGH tautologia numérica
C45 J1 HIGH parametrize vazio
C48 J1 LOW dark patch: liga uma flag de modo-teste e então asserta
C49 J1 LOW pytest.warns/assertWarns envolve mais de uma chamada
C4b J1 LOW classe de teste tem __init__ (pytest não coleta)
C50 J4 LOW log capturado nunca asserido
C51 J1 HIGH contexto pytest.raises/warns de corpo vazio
C52 J2 LOW autoconfirmação de pertinência
C55 J3 LOW assertion compara dois valores ancorados em mock
C56 J1 LOW assert síncrono de uma coroutine nunca awaitada
C57 J3 LOW assertion contra um atributo de Mock não configurado
C59 J1 HIGH comparação solta escrita como statement
C6b J3 LOW assertion sobre argumento posicional de mock via índice calculado
C6c J4 LOW truthiness de call_count do mock como oráculo
C8b J4 LOW igualdade aproximada sem tolerância explícita
C11a J2 LOW literal autoconfirmante: o teste atribui e então asserta o mesmo valor
C13b J3 LOW patch() sem autospec
D1 - LOW assertion roulette: vários asserts, nenhum com mensagem
D3 - LOW assert duplicado: a mesma assertion aparece duas vezes
D4 - LOW casos de parametrize sem nome
D5 - LOW setup inline excessivo
D6 - LOW print de debug no teste
M2 - LOW método de teste longo
PL1 J1 n/a asserts removidos em runtime
PL2 J1 n/a warnings não promovidos
PL7 J5 n/a sem gate de cobertura
PL8 J5 n/a execução para cedo

JavaScript / TypeScript and the TSX/JSX family (falsegreen-js)

O scanner falsegreen-js emite 52 códigos: os específicos de JS mais os C* compartilhados. Cada um liga para sua entrada no catálogo.

Code J Conf What it catches
C2 J1 HIGH corpo do teste sem nenhuma assertion
C5 J2 HIGH assertion sempre verdadeira
C6 J4 LOW assertion fraca: só checa que algo voltou
C7 J2 HIGH autocomparação: os dois lados são idênticos
C8 J4 LOW igualdade exata de float
C9 J4 LOW matcher de exceção amplo demais
CC J1 LOW assert comentado
C16 J6 LOW resultado depende de tempo, aleatoriedade ou sleep não controlados
C18 J2 LOW comparação de string/repr
C20 J1 HIGH assertion após return/raise/fail incondicional
C21 J1 LOW toda assertion está dentro de condicional; nenhuma roda incondicionalmente
C23 J6 LOW caminho de arquivo absoluto ou relativo ao home hard-coded
C2b J1 LOW chama código de produção mas não verifica nada
C37 J2 LOW caso de parametrize duplicado
C44 J2 HIGH tautologia numérica
C48 J1 LOW dark patch: liga uma flag de modo-teste e então asserta
C8b J4 LOW igualdade aproximada sem tolerância explícita
C11a J2 LOW literal autoconfirmante: o teste atribui e então asserta o mesmo valor
D1 - LOW assertion roulette: vários asserts, nenhum com mensagem
D3 - LOW assert duplicado: a mesma assertion aparece duas vezes
D4 - LOW casos de parametrize sem nome
D6 - LOW print de debug no teste
D7 - LOW teste anônimo: descrição vazia ou ausente
D8 - LOW número mágico numa assertion
JS1 - HIGH teste focado (it.only/fit) pula o resto da suíte
JS2 - HIGH expect(x) sem matcher
JS3 - LOW snapshot é a única assertion
JS4 - LOW teste pulado (it.skip/xit/it.todo)
JS5 - LOW query/evento async sem await (findBy*/waitFor/user-event)
JS6 - HIGH describe/suite vazio
JS7 - LOW assertion num callback de setTimeout/then sem await
JS8 - LOW mocka a unidade sob teste e a asserta diretamente
JS9 - HIGH assertion num ramo literal morto (if(false))
JS11 - LOW try/catch engole a assertion
JS13 - LOW query queryBy* (retorna null na ausência) como statement solto, nunca asserida; getBy*/findBy* lançam na ausência e são a assertion
JS15 - LOW comparação embrulhada num booleano (expect(a===b).toBe(true))
JS17 - LOW bloco de teste comentado (// it(...))
JS18 - LOW callback done em vez de async/await
JS21 - HIGH matcher referenciado mas nunca chamado (expect(x).toBe sem ())
JS22 - HIGH tabela it.each/test.each vazia
JS23 - HIGH expect.assertions(N) com menos chamadas expect() alcançáveis incondicionalmente do que N
JS24 - LOW query Cypress cy.get/find/contains sem assertion .should/.and/.then
JS25 - HIGH a única assertion fica num callback de iterador de array; roda zero vezes numa coleção vazia
JS26 - LOW fake timers instalados mas nunca avançados; o callback agendado nunca dispara
JS27 - LOW toHaveBeenCalled* como único oráculo sobre um dublê criado localmente; verifica a fiação, não o comportamento
JS29 - LOW cadeia expect(...).resolves/.rejects como statement solto, sem await nem return
JS30 - HIGH assertion literal-vs-literal (expect(2).toBe(3)); os dois operandos fixos em parse time
JS31 - LOW try/catch engole um throw possível sem assertion sobre a exceção
M2 - LOW método de teste longo
PL7 J5 n/a sem gate de cobertura
PL8 J5 n/a execução para cedo
PL10 J1 n/a passWithNoTests

Robot Framework (robotframework-falsegreen)

O scanner robotframework-falsegreen emite 30 códigos: os específicos de R* mais os C* compartilhados. Cada um liga para sua entrada no catálogo.

Code J Conf What it catches
C2 J1 HIGH corpo do teste sem nenhuma assertion
C3 J1 HIGH assert dentro de um try cujo except engole o erro
C5 J2 HIGH assertion sempre verdadeira
C6 J4 LOW assertion fraca: só checa que algo voltou
C7 J2 HIGH autocomparação: os dois lados são idênticos
C9 J4 LOW matcher de exceção amplo demais
CC J1 LOW assert comentado
C16 J6 LOW resultado depende de tempo, aleatoriedade ou sleep não controlados
C20 J1 HIGH assertion após return/raise/fail incondicional
C21 J1 LOW toda assertion está dentro de condicional; nenhuma roda incondicionalmente
C23 J6 LOW caminho de arquivo absoluto ou relativo ao home hard-coded
C2b J1 LOW chama código de produção mas não verifica nada
C31 J4 LOW resultado da captura descartado
C32 J1 LOW skip sem motivo
C37 J2 LOW caso de parametrize duplicado
C44 J2 HIGH tautologia numérica
C9b J4 n/a RequestsLibrary expected_status=any
C11a J2 LOW literal autoconfirmante: o teste atribui e então asserta o mesmo valor
D2 J4 n/a fluxo de controle a nível de teste
M2 - LOW método de teste longo
PL9 J1 n/a opção de execução skip-on-failure
R1 J1 n/a verde forçado
R2 J1 n/a keyword verificadora oca
R3 J1 n/a test cases num .resource
R4 J1 n/a No Operation
R5 J1 n/a [Template] vazio
R6 J4 n/a Should Be True sobre uma string literal
R7 J1 n/a keyword de [Template] oca
R8 J4 n/a verificação só no Setup
R8b J4 n/a verificação só no Teardown

Semantic codes, skill-only (all languages)

Só a skill LLM detecta estes. Ficam em J2/J3/J4 e precisam de uma leitura de intenção que um AST não decide. Cada um liga para o catálogo semântico.

Code J What it catches
S1 J4 intent mismatch
S2 J4 oráculo irrelevante
S3 J2 valor esperado plausível-mas-errado
S4 J4 oráculo não distingue o correto de um bug provável
S5 J3 testa o framework, não o código
S6 J4 só happy-path contra um contrato declarado
S7 J2 esperado tirado da saída
S8 J3 retorno de mock chega na assertion por uma indireção
S9 J2 arranjo autorrealizável
S10 J4 asserta o log, não o efeito
S11 J4 assertion só negativa sobre um filtro de segurança
S12 J3 patcheia a lógica central em vez de uma borda externa
S13 J6 passa só por estado compartilhado que um irmão montou
S14 J2 saída de modelo gravada como oráculo
S15 J6 laço de retry/poll feito à mão mascarando flakiness
S16 J4 verificação de chamada como único oráculo
S17 J4 cegueira de oráculo no caminho de exceção
S18 J3 valor de stub impossível pelo contrato
S21 J2 assertion de LLM/agente que se autojulga

Patterns characteristic of each level

A mesma classe de false-green aparece no nível em que o teste roda. Estes são os clusters típicos.

Unit (the bulk of false-greens)

  • always-true / tautologia: C5, C7, C52, JS30
  • sem oráculo / corpo vazio: C2, C2b, JS2
  • asserta o próprio dublê / mock: C13b, C55, C11a, JS8, JS27, S8 (stub-echo), S16
  • condicional-only / não roda: C21, JS9, C20 (após um terminador), JS25 (iterador sobre coleção vazia)
  • coroutine nunca awaitada: C56; comparação solta: C59; atributo de Mock não configurado: C57
  • semânticos: S5 (testa o framework), S3 (valor esperado plausível-mas-errado), S6

Integration (crosses the boundary: I/O, DB, HTTP, collaborator)

  • oráculo do request desligado: C9b (expected_status=any)
  • captura sem asserir: C50 (caplog / assertLogs)
  • mockar a unidade sob teste em vez da borda: S12
  • round-trip que só confirma o que você mandou (DB / HTTP liveness vazio)
  • semânticos: S9, S10, S11, S18 (stub com valor impossível pelo contrato)

E2E (the full stack: browser, flow, hardware)

  • sleep como sincronização em vez de Wait Until: C16
  • age e só loga/screenshot sem verificar: C2b em browser/login, R4 (só No Operation)
  • forced-green: R1 (Pass Execution), R2 (keyword verificadora oca)
  • presença de elemento ou Should Be True sobre string como único oráculo: R6
  • semânticos: S1 (intent mismatch: o nome promete o que o corpo não verifica), S2 (oráculo irrelevante)

Diagnostics (off by default, not false-green)

D1, D3-D8, M2 são higiene e manutenibilidade (fluxo de controle, teste longo). Ligam com --diagnostics. Não são a tese false-green; ver what we do not flag.