Conceitos importantes em testes
Mainnet Forking
O mainnet forking é uma técnica usada nos testes de blockchain, na qual se pega um número especÃfico de bloco e uma referência para um nó de blockchain (como o Geth) e se copia toda a informação de estado relevante até aquele número de bloco. Esse estado clonado permite que os desenvolvedores executem testes contra ele. Essa estratégia é comumente implementada contra a mainnet, especialmente quando se testam interações com códigos de terceiros que já estão implantados.
Uma das vantagens significativas do mainnet forking é a capacidade de executar todos os testes localmente, reduzindo significativamente tanto os riscos quanto os custos associados aos testes. Como a rede local reflete o estado da cadeia, ela também pode ser revertida ao seu estado original após cada teste, permitindo testes eficientes e isolados. Além disso, o estado local pode ser manipulado conforme necessário para simular cenários especÃficos que podem não estar presentes no estado do fork. O mainnet forking é, portanto, uma ferramenta poderosa, especialmente para testar cenários que não são facilmente cobertos pelos testes unitários e de integração.
Desenvolvimento Orientado por Testes
O Desenvolvimento Orientado por Testes (Test Driven Development - TDD) é uma metodologia na qual os testes são escritos antes do código real. Esse enfoque tenta garantir que todo o código esteja alinhado com as especificações impostas pelos testes. O fluxo de trabalho envolve escrever os testes, verificar que eles estão falhando, escrever o código e confirmar que os testes passaram. É importante notar que o código que faz o teste passar deve ser a quantidade mÃnima necessária, evitando que qualquer código desnecessário se infiltre no projeto. Se os testes falharem, é porque os testes ou o código contêm um erro.
Consequentemente, o processo é repetido após uma rodada de reestruturação do código e dos testes. No final de uma rodada de TDD, é comum revisar novamente toda a base de código e estruturá-la de forma mais organizada, por exemplo, externalizando o código em bibliotecas ou componentes individuais e executando novamente o conjunto de testes para garantir que nenhum erro tenha sido introduzido. Embora o TDD não possa garantir código livre de erros, geralmente oferece garantias mais fortes do que adaptar um conjunto de testes posteriormente. Ele também acelera o processo de escrita de testes, pois os desenvolvedores frequentemente escrevem os testes no final do processo de desenvolvimento, o que pode levar à fadiga e à falta de cobertura nos cenários de teste.
O TDD é aplicado principalmente a testes unitários, mas também pode ser usado para testes de integração, assumindo que os componentes estão bem definidos e não é provável que mudem. Embora frequentemente seja percebido como uma desvantagem, o TDD obriga os desenvolvedores e gerentes de projeto a refletirem primeiro sobre a arquitetura e o design de seus contratos inteligentes e a estabelecer um conjunto de requisitos do usuário que o sistema precisa atender. No entanto, vale notar que todas as vantagens do TDD têm um custo em termos de velocidade de desenvolvimento, especialmente quando os desenvolvedores ainda não estão familiarizados com o desenvolvimento orientado por testes.
Cobertura de testes
A cobertura de testes (test coverage) de contratos inteligentes refere-se à medida em que o código do contrato foi executado e verificado por meio de testes automatizados. Em termos simples, é uma métrica que indica qual porcentagem do código foi testada através de casos de teste especÃficos.
Uma cobertura de testes de 100% é o objetivo, mas é difÃcil de alcançar na prática. No entanto, os desenvolvedores devem aspirar cobrir todas as funções e casos de uso crÃticos do contrato. Ferramentas de cobertura de código, como o solidity-coverage, podem ajudar a medir quais partes do código foram testadas.
Importância da cobertura de testes
Segurança:
Garante que todas as partes crÃticas do contrato foram verificadas e são seguras contra possÃveis vulnerabilidades.
Funcionalidade:
Verifica que todas as funções do contrato operem como esperado sob diversas condições e entradas.
Confiança:
Proporciona confiança tanto aos desenvolvedores quanto aos usuários de que o contrato foi exaustivamente testado e é confiável.
Manutenção:
Facilita a manutenção e atualização do contrato, garantindo que qualquer mudança ou adição ao código também seja testada adequadamente.
Tipos de cobertura de testes
Cobertura de Linhas:
Mede a porcentagem de linhas de código que foram executadas durante os testes.
Cobertura de Funções:
Mede a porcentagem de funções que foram chamadas pelo menos uma vez durante os testes.
Cobertura de Condições:
Mede a porcentagem de condições booleanas possÃveis que foram avaliadas como verdadeiras e falsas durante os testes.
Cobertura de Ramos:
Mede a porcentagem de caminhos de execução (ramificações) que foram seguidos durante os testes, incluindo bifurcações em declarações como
if
,else
,switch
, etc.
Ferramenta para medir a cobertura de testes
Fixtures
Os fixtures são cenários de teste que são executados uma vez e, em seguida, são lembrados por meio de capturas do estado da blockchain. Entre os benefÃcios que eles oferecem, podemos destacar:
Eliminam a necessidade de implantar o contrato novamente antes de fazer um novo teste.
Garantem que os testes sejam executados sempre sob as mesmas condições iniciais, o que é crucial para a consistência e confiabilidade dos testes.
Permitem que cada teste seja executado em um ambiente limpo e isolado, evitando que o estado de um teste afete o outro.
Ajudam a reduzir o tempo de configuração para cada teste individual, ao definir um estado inicial comum para um grupo de testes.
O Hardhat permite configurar fixtures em seu ambiente de testes.
Last updated