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 | só 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:
C2bem browser/login,R4(sóNo Operation) - forced-green:
R1(Pass Execution),R2(keyword verificadora oca) - presença de elemento ou
Should Be Truesobre 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.