Eu tenho um software bastante grande que pega certos tipos de arquivos e os visualiza / cria uma série de botões para manipulação da imagem plotada. Sinto que estou encontrando bugs / partes de código que na verdade não funcionam uma vez por semana, mas estou tendo dificuldades para entender como posso escrever testes para este software?
Entendo como os testes são importantes para projetos como bibliotecas e APIs, você simplesmente escreve testes que usam essas funções.
Mas e o software de visualização? Parece exigir uma abordagem diferente devido aos elementos visuais envolvidos.
Preciso escrever um programa ou equipamento de teste que execute e chame manualmente todas as operações, desde que eu possa usar os dados?
Qual abordagem devo usar para começar a escrever testes para validar que corrigi os bugs e para me alertar se o código quebrar novamente?
Há uma pergunta relacionada, mas não duplicada, a respeito de quando você deve fazer o teste de unidade. Como estou descobrindo bugs, quero escrever testes para ajudar a impedir que o software volte novamente.
fonte
Tudo tem uma interface. Quando visto meu chapéu de teste, uso uma visão de mundo específica para escrever um teste:
No seu caso, seu sistema possui três partes principais:
Aliás, isso me parece muito com a arquitetura original do Model-View-Controller. Idealmente, esses três elementos exibem acoplamentos frouxos - ou seja, você define limites claros entre eles com interfaces bem definidas (e, portanto, bem testáveis).
Uma interação complexa com o software pode ser traduzida em pequenas etapas que podem ser formuladas em termos dos elementos do sistema que estamos testando. Por exemplo:
Parece ser fácil testar manualmente e difícil testar automatizado. Mas vamos traduzir essa história para o nosso sistema:
Agrupados por componente, terminamos com as seguintes propriedades para testar:
Se não decompormos o problema do teste em subtestes menores, o teste se tornará realmente difícil e realmente frágil. A história acima também pode ser implementada como "quando eu carrego um arquivo específico e defino o controle deslizante para um valor específico, uma imagem específica é renderizada". Isso é frágil, pois quebra quando qualquer elemento do sistema é alterado.
Os testes granulares também têm a grande vantagem de me permitir evoluir o sistema sem medo de quebrar nenhum recurso. Como todo o comportamento necessário é medido por um conjunto de testes completo, os testes serão avisados caso algo pare. Como são granulares, eles me indicarão a área problemática. Por exemplo, se eu acidentalmente alterar a interface de qualquer componente, apenas os testes dessa interface falharão e nenhum outro teste que use indiretamente essa interface.
Se o teste é fácil, isso requer um design adequado. Por exemplo, é problemático quando conecto os componentes em um sistema: se eu quiser testar a interação de um componente com outros componentes em um sistema, preciso substituir esses outros componentes por stubs de teste que permitam registrar, verificar, e coreografar essa interação. Em outras palavras, preciso de algum mecanismo de injeção de dependência e as dependências estáticas devem ser evitadas. Ao testar uma interface do usuário, é uma grande ajuda quando essa interface do usuário é programável.
Naturalmente, a maior parte disso é apenas uma fantasia de um mundo ideal, onde tudo é dissociado e facilmente testável e os unicórnios voadores espalham amor e paz ;-) Embora qualquer coisa seja fundamentalmente testável, muitas vezes é proibitivamente difícil fazê-lo, e é melhor usos do seu tempo. No entanto, os sistemas podem ser projetados para serem testados e, normalmente, até os sistemas independentes de teste apresentam APIs internas ou contratos que podem ser testados (caso contrário, aposto que sua arquitetura é uma porcaria e você escreveu uma grande bola de barro). Na minha experiência, mesmo pequenas quantidades de teste (automatizado) afetam significativamente a qualidade.
fonte
Comece com um arquivo conhecido que produz uma imagem esperada. Verifique cada pixel. Cada um deve ter um valor esperado para um arquivo de teste conhecido e feito à mão. Você deve ter uma imagem de saída esperada para compará-la. Qualquer coisa que esteja "desativada" significa um erro no seu código.
Expanda seu arquivo de teste para que a imagem de saída seja alterada e atinja todos os recursos do seu software.
O script seria útil para esse tipo de teste de caixa preta. Um script simples que executa a versão mais recente do seu software para a entrada conhecida e a saída esperada.
O Teste de Unidade, por outro lado, deve ser um teste de caixa branca, onde você pega o menor pedaço possível de software, normalmente uma função ou qualquer outra coisa, e vê se ele se comporta como o esperado. Você pode ver que cor de pixel ele retorna ou o que for. Nesse caso, seu código se comporta como uma biblioteca, com APIs para todas as outras seções do seu código.
Se tudo estiver dobrado em um arquivo .c com todas as funcionalidades incluídas
main()
, você terá problemas maiores do que como testar.fonte