ShortArrow/test-design

Derivação de casos de teste, acionado pelos momentos que produzem casos fracos: prestes a escrever uma lista de testes que é apenas o caminho feliz reformulado, prestes a derivar testes lendo a implementação que eles verificam, prestes a testar o limite que a especificação nomeia e não o outro, prestes a enumerar os papéis que a especificação lista e pular o chamador que ela esqueceu, prestes a variar uma condição de cada vez a partir do caminho feliz, prestes a desenhar uma tabela de estados ou de decisão sem amarrar cada linha a um teste, prestes a escrever um resultado esperado com "ou" nele, prestes a pular os caminhos de erro como improváveis, prestes a deixar um caminho não implementado e não testado, ou prestes a avaliar uma suíte como adequada apenas lendo-a. Um teste derivado da implementação passa por construção; cobertura conta classes, não testes. Use ao escrever um plano ou lista de testes, quando um caso de uso é a especificação em mãos, ao adicionar testes a código existente, ao revisar uma suíte em busca de lacunas, e quando uma suíte está toda verde e prova pouco.

O que é test-design?

Esta skill aborda a disciplina de **design de casos de teste**, focando em como derivar testes eficazes a partir de **especificações**, e não da implementação. Ela é útil para qualquer desenvolvedor ou engenheiro de qualidade que queira criar suítes de teste robustas que realmente detectem defeitos, em vez de apenas confirmar o comportamento atual do código. A skill lista os momentos comuns em que testes fracos são gerados (como testar apenas o caminho feliz, derivar testes do código, ou deixar de testar limites não nomeados) e fornece alternativas concretas. Ela introduz conceitos como **classes de equivalência** (contar classes, não testes), **análise de valor limite** (testar ambos os lados de cada limite), **tabelas de decisão** (cobrir combinações de condições), e **tabelas de estado** (garantir que cada transição, incluindo as proibidas, tenha um teste). A skill também enfatiza que caminhos de erro, caminhos não implementados e casos de uso (fluxos alternativos e de exceção) são classes que merecem testes. Ela é agnóstica de plataforma, funcionando para qualquer linguagem ou framework de teste (como pytest, JUnit, etc.), e é fundamentada em padrões da indústria como o ISTQB CTFL. O objetivo final é transformar a cobertura de teste de uma métrica vazia em uma ferramenta significativa, contando classes e regras contra a especificação.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ShortArrow/skills/tree/HEAD/skills/test-design

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Design de testes

Os casos decidem o que a suíte pode capturar. Tudo o que vem depois — o harness, o executor, a contagem — apenas executa essa decisão.

Os momentos que isso substitui

Prestes a…Em vez disso…
escrever o caminho feliz e pararpercorrer o espaço de entrada: para cada parâmetro, suas classes e seus limites
derivar casos da implementaçãoderivá-los da especificação, e deixar a implementação surpreender você
testar com um valor confortáveltestar o último valor dentro e o primeiro valor fora de cada limite
testar o limite que a especificação nomeiatodo intervalo tem duas pontas; a que a frase deixou de fora ainda é um limite
enumerar os papéis que a especificação listaadicionar o chamador que ela esqueceu: sem papel, não autenticado, não atribuído
variar uma condição do caminho felizconstruir a tabela de decisão e cobrir as regras onde duas condições falham juntas
desenhar uma tabela de estado e seguir em frentecolocar um id de teste em cada linha; a linha que diz "não permitido" mais do que todas
escrever "rejeitado, ou aceito desde que…" como resultado esperadoum resultado por caso; uma especificação que não consegue decidir é uma questão em aberto, não um teste
pular caminhos de erro como improváveiscada modo de falha é uma classe: entrada inválida, recurso ausente, negado, timeout, parcialmente concluído
deixar um caminho não implementado sem teste, um marcador de skip ou um stub que ninguém verificaescrever um teste de que o caminho é recusado como não implementado hoje; ele passa agora e fica vermelho no dia em que alguém o construir (abaixo)
testar um recurso pelo seu fluxo principaller os fluxos alternativos e de exceção do caso de uso; cada um é uma classe
avaliar uma suíte apenas lendo-acontá-la contra a especificação: classes, ambos os limites, regras, transições
adicionar um quinto teste a uma classe cobertagastá-lo em uma classe descoberta — o quinto compra tempo de execução e nenhuma cobertura

Atacar a especificação, não a implementação

Um teste escrito ao ler o código afirma o que o código faz. Ele passa na chegada, codifica os bugs atuais como expectativas, e suas falhas após uma mudança dizem "o código mudou", o que já era sabido. Isso é medido, não suspeitado: em 24 repositórios Java, oráculos gerados por LLM tenderam a capturar o comportamento real do programa em vez do seu comportamento esperado (Konstantinou, Degiovanni, Papadakis, arXiv:2410.21136).

Derive a partir do que a coisa deveria fazer — a especificação, o formato do fio, o contrato — e só então execute. A única exceção legítima é o teste de caracterização que deliberadamente fixa o comportamento atual, e é marcado como tal para que ninguém mais tarde confunda um bug fixado com um requisito.

Um cheiro útil: se todo teste estava verde na sua primeira execução, a suíte foi derivada da implementação, independentemente da intenção.

Classes de equivalência: conte classes, não testes

Entradas que o código não consegue distinguir formam uma classe, e um teste por classe é suficiente — o segundo ao quinto custam tempo de execução e não provam nada de novo. A disciplina funciona em ambos os sentidos: nenhuma classe deixada descoberta, nenhuma classe coberta duas vezes por acidente.

Uma suíte de dezessete testes parece completa. Se ela é depende de quantas classes esses dezessete cobrem, e esse número não aparece na saída de nenhum executor. Ele tem que ser contado contra o espaço de entrada manualmente — que é o que um plano de teste é.

As classes que a especificação lista são a metade fácil. Uma tabela de papéis com três linhas tem uma quarta classe, a requisição que não corresponde a nenhuma delas, e é a que uma suíte construída a partir da tabela nunca contém. Para cada parâmetro, escreva as classes inválidas ao lado das válidas antes de escrever qualquer caso: tipo errado, ausente, fora de todo valor listado, o chamador sem direitos nenhum.

O syllabus afirma isso como uma regra em vez de um hábito: na partição de equivalência os itens de cobertura são as partições, 100% significa toda partição identificada exercitada "incluindo partições inválidas", e as partições "não devem se sobrepor e devem ser conjuntos não vazios" (ISTQB CTFL v4.0.1 §4.2.1). Com vários parâmetros ele nomeia o critério mais fraco Each Choice — toda partição de cada parâmetro uma vez, combinações ignoradas — que é o nível que a maioria das suítes atinge sem saber seu nome, e onde a tabela de decisão abaixo começa.

Limites, porque é onde estão as falhas

Off-by-one é a falha aritmética mais comum, e é invisível em todos os lugares exceto na borda. O par que importa em cada limite é o valor do limite e seu vizinho mais próximo do outro lado da linha, que é o BVA de 2 valores (CTFL v4.0.1 §4.2.2); o BVA de 3 valores adiciona o vizinho do lado de dentro também, e o syllabus mostra o que isso compra: uma verificação pretendida como x ≤ 10 mas escrita como x = 10 passa tanto para 10 quanto para 11, e apenas 9 a pega. As arestas recorrentes: vazio, exatamente um, muitos; zero e negativo; o máximo declarado e um além dele; o valor que é exatamente o buffer, o limite, o timeout.

Um par concreto desta máquina: uma verificação de PATH que está ok em 8.190 caracteres e deve falhar em 8.192 tem que ser testada nesses dois valores. Passar em 4.000 e 12.000 estabelece quase nada sobre a linha entre eles.

Onde o limite é uma pré-condição declarada, o valor além dele é um bug do chamador em vez de um caso com resultado esperado; design-by-contract decide qual dos dois uma determinada aresta é, e o teste então verifica o que se aplica.

O lado que a especificação não nomeou

"Até 10 MB" nomeia uma ponta de um intervalo. A outra ponta existe quer a frase a mencione ou não, e casos derivados do texto param onde o texto para: uma suíte com o limite superior testado em −1, 0 e +1 bytes e nada abaixo de 1.024 fez análise de limite em metade de um intervalo. A definição não tem lado: "os valores mínimo e máximo de uma partição são seus valores de limite" (CTFL v4.0.1 §4.2.2). Escreva ambos para cada partição primeiro, depois pegue cada um com seu vizinho mais próximo na partição adjacente. O lado não nomeado é geralmente zero, vazio ou um, e a especificação geralmente é silenciosa sobre ele porque ninguém decidiu.

Mova duas condições de uma vez

Uma suíte construída mudando uma condição do caminho feliz cobre todo valor de toda condição e quase nenhuma de suas combinações: formato errado, tamanho acima, contagem acima, cada um sozinho, e nenhum caso onde dois falham juntos. Qual erro vence quando ambos se aplicam raramente está na especificação também, então o caso ausente esconde uma decisão ausente.

Disponha as condições como uma tabela de decisão e conte as regras, depois cubra as regras onde duas condições falham de uma vez e a regra onde uma restrição de papel e uma restrição de formato ambas se aplicam. No teste de tabela de decisão os itens de cobertura são as colunas que contêm combinações viáveis, e 100% significa toda coluna desse tipo exercitada (CTFL v4.0.1 §4.2.3); o syllabus acrescenta que a tabela "ajuda a encontrar quaisquer lacunas ou contradições nos requisitos", que é a decisão ausente acima surgindo por si só. O mesmo documento pode ser lido como totalmente coberto sob Each Choice e um quarto coberto sob as colunas, e apenas o segundo número diz algo sobre as combinações. Quando a contagem de regras é o produto de um conjunto de flags, a correção mais barata é a montante: state-first colapsa as flags nos estados que podem ocorrer, e a tabela encolhe para eles.

Uma tabela é uma afirmação sobre a suíte

Uma tabela de estado, uma tabela de decisão, a lista de fluxo de um caso de uso: cada linha afirma que um teste existe para ela. Coloque o id do teste na linha. Uma linha sem id é uma classe descoberta, e a linha que diz "não permitido" é a mais provável de estar vazia, porque escrever a proibição pareceu já ter lidado com ela. A transição proibida — o segundo envio enquanto um está em andamento — é o teste, e a guarda que deveria impedi-lo é a coisa sob teste.

A tabela de estado torna essa linha explícita: uma transição inválida é uma célula vazia, e o mais forte dos três critérios que o syllabus define, cobertura de todas as transições, exige tentar cada uma delas — um por caso de teste, para que um defeito não possa mascarar outro (CTFL v4.0.1 §4.2.4). Cobertura de transições válidas, o 0-switch onde a maioria das suítes para, nunca toca nessas células, é assim que uma linha "não permitido" não testada permanece verde.

Depois leia os dois documentos um contra o outro. Um teste cujo caminho discorda da tabela (a tabela diz falhou → enviando, o teste vai falhou → selecionado → enviando) significa que um deles está errado, e nada além da comparação descobre qual. Auto-transições e as transições para fora do estado de falha também contam como linhas.

Um resultado por caso

"Rejeitado, ou se aceito, nenhum dado corrompido permanece após o envio" não pode passar ou falhar. Aparece honestamente, quando a especificação nunca disse o que acontece com um arquivo de zero bytes e o autor se recusou a inventar uma resposta, e sobrevive à revisão porque o caso está visivelmente presente. A disjunção se esconde na coluna esperada. A forma correta é uma pergunta para quem possui a especificação, listada como tal, e nenhum teste para aquela classe até que seja respondida.

Caminhos de erro também são classes

Os caminhos infelizes são onde o código não testado se acumula, porque nada os exercita no uso normal — um detentor de lock morrendo no meio da execução, uma pasta mapeada que não existe, entrada com o campo esperado faltando. Cada um é uma classe de equivalência com a mesma reivindicação a um teste que qualquer intervalo de entrada. Uma suíte que apenas prova que a ferramenta funciona quando tudo coopera testou a demo, não a ferramenta.

Casos de uso enumeram as classes antes de haver código

Um caso de uso é uma especificação já cortada em classes: um fluxo principal, cada fluxo alternativo, cada fluxo de exceção, e a pré-condição sob a qual cada um pode ser iniciado. Quem o escreveu fez a enumeração que esta skill pede — os fluxos alternativos e de exceção são os caminhos de erro — então uma suíte que exercita o fluxo principal cobriu uma classe das N que o documento lista.

Leia os fluxos do caso de uso e dê a cada um seu teste, depois verifique as pré-condições, porque um fluxo só é acessível quando sua pré-condição pode ser verdadeira. Uma verificação de paridade para páginas traduzidas tem um fluxo principal (ambos os idiomas editados e commitados), um fluxo alternativo (uma edição unilateral declarada como exceção), e dois fluxos de exceção que só aparecem depois que as pré-condições são escritas: a árvore está suja, então a desatualização ainda não pode ser julgada; o histórico foi reescrito, então um commit declarado não resolve mais. Ambos foram atingidos em um site dentro de uma semana. O caminho feliz sozinho não teria mostrado nenhum.

Se um fluxo de exceção pode realmente ocorrer não é resolvido por quão improvável parece. O envelope operacional diz o que está fora do escopo e a análise de perigos diz o que resta; ambos vivem em assurance-case, e esta skill pega a lista que eles produzem em vez de podá-la por intuição.

Cobertura é um número sob um critério nomeado

Um documento de teste medido de três maneiras: 100% das condições, 90,9% MC/DC, 25% das regras de decisão. Todos os três são verdadeiros para o mesmo arquivo, então um número de cobertura sem seu critério não diz nada, e um número cujo critério é escolhido após a contagem diz menos ainda. Nomeie-o antes de contar, nos próprios termos do syllabus para que o número possa ser verificado: cobertura de partição e Each Choice (§4.2.1), BVA de 2 ou 3 valores (§4.2.2), colunas de tabela de decisão (§4.2.3), todos os estados, transições válidas ou todas as transições (§4.2.4). MC/DC não está no syllabus Foundation; ele vem dos padrões de segurança (DO-178C, ISO 26262), e listá-lo ao lado dos outros sem dizer isso é o tipo de citação mista que parece rigor. O resto do que um número deve ao seu leitor está em measured-claims.

Verificando uma suíte: conte, não julgue

Perguntar se uma suíte é adequada retorna os pontos cegos que a produziram. Uma segunda sessão no mesmo modelo os compartilha, e o mesmo acontece com a mesma pessoa um dia depois. O syllabus chama isso de "alguma independência", o segundo de seus quatro níveis, e diz de onde vem o valor: "diferenças entre os vieses cognitivos do autor e do testador" (CTFL v4.0.1 §1.5.3). Uma segunda sessão no mesmo modelo compartilha os vieses e mantém apenas o rótulo. O passo que não os compartilha é contar: liste as classes da especificação e marque as que têm um teste, liste ambos os limites de cada intervalo, liste as regras da tabela de decisão, liste as linhas de cada tabela de estado, e cite o arquivo e a linha de cada lacuna. Se um valor esperado está certo continua sendo um julgamento e fica com um leitor que não o escreveu; se uma classe tem um teste é aritmética. Se a contagem foi amostrada em vez de exaustiva, o relatório diz amostrado. A forma refute-por-padrão para o veredito está em adversarial-verify; esta skill fornece o que contar.

Quando a requisição remove uma classe

"O envio duplo não pode acontecer porque o botão está desabilitado, descarte essa linha" remove uma classe da suíte com base na força de uma guarda em uma camada. Faça o que foi pedido, e diga em uma frase qual classe está agora descoberta e o que a alcançaria: a máquina de estados ainda aceita um segundo envio de qualquer chamador que não seja o botão. Uma linha deletada com essa frase é uma decisão; uma linha deletada sem ela é uma lacuna que ninguém encontrará novamente.

Um caminho não implementado tem um teste que diz isso

Um caminho deixado de fora desta mudança de propósito, um papel que esta release não suporta, um formato ainda não analisado, um branch que lança NotImplementedException ou chama todo!(), ainda é uma classe da entrada, e a suíte registra o que acontece lá hoje. Escreva o teste de que o caminho é recusado como não implementado: a exceção ou o valor de erro que ele levanta, o item de menu que está ausente, a requisição que responde "não suportado".

Esse teste passa agora e faz dois trabalhos. Ele coloca a lacuna na lista da suíte, onde um leitor contando classes a encontra, em vez de em um comentário ou ticket. E ele fica vermelho no dia em que alguém implementa o caminho, que é o momento em que seus casos reais têm que ser escritos; o teste com falha é o lembrete, e é substituído, não deletado.

Um marcador de skip ou um teste pendente não é um teste; é um espaço reservado que a suíte trata como sucesso e ninguém revê.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

ShortArrow/interface-design

Deciding how a screen looks and behaves, triggered by the moments that hand the decision to the user unworked: about to ask which layout, which colour, which placement, how to draw a diagram, how wide a pane, how to split a view; about to call a visual choice a matter of taste; about to treat "it looks fine" as having checked it; about to ship a control sized by eye; about to read an automated accessibility pass, or a Lighthouse score of 100, as a clean bill of health. Most of these have an answer in a published standard, a measurable threshold, or one screenshot — WCAG 2.2 fixes contrast, target size, reflow and focus; a design system fixes spacing and components; axe-core finds about 57% of WCAG issues, and Lighthouse's accessibility score is that same engine weighted, so both leave the rest to a person. What survives is a genuine question, asked with the evidence attached. Use before asking any question about appearance, layout or interaction, and before calling

ShortArrow/library-design

Designing a library — a published package, or an in-app module from the moment it has a second consumer. The implementation stays editable forever, while the public API, the dependency set, the performance characteristics and every observable behaviour freeze at first external use (Hyrum's law). Five duties to the caller: take no control, add no hidden cost (zero-cost abstraction as the bar), hold no hidden state, hide no failure, block no escape. Use when designing or reviewing a public API, when extracting shared code into a module, when asked to "make this reusable", when a signature-compatible change alters an observable behaviour, and when an application is being shaped around a framework's types and lifecycle.

Habilidades Relacionadas