WEB3DEV

Cover image for Como Executar Testes de Unidade para Contratos Inteligentes com o Hardhat
Fatima Lima
Fatima Lima

Posted on

Como Executar Testes de Unidade para Contratos Inteligentes com o Hardhat

Image description

Introdução

Uma das ferramentas mais fundamentais e úteis que um desenvolvedor de blockchain tem em seu arsenal é fazer chamadas de contrato. Ao trabalhar em projetos complexos e com vários contratos, é muito provável que você não implante um único arquivo de contrato inteligente para toda a produção. Você pode até implantar alguns contratos antes de outros.

Fazer chamadas de contrato é uma maneira flexível de os contratos implantados interagirem com outros na blockchain.

Dessa forma, em vez de ter uma longa e confusa linha de código, você tem uma rede de contratos interagindo entre si na blockchain.

Ao longo deste tutorial, você aprenderá a:

  • Instalar e configurar o Hardhat.
  • Cria um contrato inteligente fictício.
  • Usar o Hardhat para implantar na rede Alfajores da Celo.
  • Criar um script de teste proficiente em um Hardhat.
  • E fazer chamadas de contrato em seu contrato implantado usando scripts de teste do Hardhat.

Pré-requisitos

Para aproveitar ao máximo este tutorial, você deve ter uma compreensão básica e fundamental do seguinte:

  • Rede de testes Alfajores da Celo.
  • Faucets (torneiras).
  • Hardhat. Não se preocupe, você vai instalar o Hardhat ao longo deste tutorial.
  • O nó node e Gerenciador de Pacote de Nós npm. Este tutorial usará o gerenciador de pacotes de nós.

Você deve ter o gerenciador de pacotes de nós npm pré-instalado. Siga os links para obter mais informações sobre a instalação do node e do gerenciador de pacotes npm.

Requisitos

  • Neste tutorial, precisaremos da Metamask. Instale-a AQUI.
  • Certifique-se de ter a versão NodeJS 12.0.1+ instalada.

Uma breve definição das Palavras-chave

Antes de começar a usar este tutorial, aqui está uma rápida recapitulação das palavras-chave com as quais você trabalhará durante este tutorial.

Alfajores da Celo

O Alfajores da Celo é uma rede de teste executada pelo time da Celo. É uma simulação de blockchain que permite implantações e testes de contratos inteligentes em uma blockchain de teste. Embora seja considerada uma blockchain de teste, ela simula principalmente a implantação e o teste de contratos na Blockchain da Celo.

Funciona exatamente com a mesma eficácia que nas redes principais da Celo, exceto pelo fato de você chamar as transações usando fundos de uma faucet ou torneira (dinheiro da rede de teste).

Faucets

Elas são simplesmente dinheiro de redes de teste depositado em sua carteira apenas para interagir com uma Blockchain de teste.

Para fazer transações na Rede de teste Alfajores, você precisa de tokens da rede de teste CELO.

Seguindo este tutorial, você precisará de faucets CELO para implantar e fazer transações na blockchain Alfajores da Celo.

Obter faucets é sempre tão fácil quanto dar esses pequenos passos:

  1. Vá até o site da faucet para a rede de teste de que você precisa. Por exemplo, uma faucet Alfajores da Celo lhe dará tokens para interagir com a rede de teste Alfajores da Celo (que você também usará neste tutorial).
  2. Copie o endereço de sua carteira Metamask ou da carteira de sua preferência e cole-o na guia.
  3. Conclua o processo de autenticação, normalmente, com o captcha I am not a robot. Clique no botão enviar e aguarde cerca de 15 a 90 segundos, dependendo da rede solicitante e você notará um aumento no saldo de sua carteira.

HardHat

Este é um ambiente de desenvolvimento Ethereum que é executado na ether-js e em outras bibliotecas básicas compatíveis com a EVM. Ele é usado para compilar, executar e implantar contratos inteligentes Solidity.

Contratos de Chamada

O que são as chamadas de contrato mencionadas neste tutorial?

Fazer uma chamada de contrato significa simplesmente chamar as funções de um contrato implantado para outro contrato implantado na blockchain.

As chamadas podem ser feitas para recuperar dados de uma função de consulta, para uma função de pagamento para efetuar pagamentos ou até mesmo para uma função de modificador para modificar o estado de uma variável.

Agora que você se lembrou das ferramentas de que precisaremos, é hora de colocar a mão na massa e escrever código para entender o objetivo deste tutorial.

Instalação e Configuração do Hardhat

Para começar a codificar a parte deste tutorial, você precisa instalar o Hardhat.

Nas próximas etapas, você aprenderá a instalar o Hardhat em seu ambiente de trabalho local usando o Yarn em seu gerenciador de pacotes preferido.

  1. Crie um espaço de trabalho em seu editor de código preferido.
  2. Vá para o terminal de seu ambiente de trabalho e execute o código npm init -y. Isso serve para inicializar um arquivo package.json.
  3. Execute o comando npm install --save-dev hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers @nomicfoundation/hardhat-toolbox. Execute também o comando npm i hardhat-deploy em seu terminal para instalar todas as dependências necessárias para este tutorial.
  4. Em seguida, execute o comando npx hardhat para iniciar o ambiente de desenvolvimento do Hardhat. Você será solicitado a escolher a linguagem com a qual trabalhará.
  5. Clique em Enter duas vezes para ativar a opção Create a Javascript Project e para verificar o local do projeto. Você notará uma nova estrutura de pastas no explorador de arquivos do editor de código.

Agora que você instalou e configurou com sucesso seu ambiente de desenvolvimento Hardhat, em seguida criará os contratos de exemplo necessários para testar as chamadas de contrato.

Criação dos seus Contratos Inteligentes

Para simular uma chamada de contrato, você precisará criar dois contratos inteligentes. Esses dois contratos serão implantados na Blockchain Celo.

Um dos contratos terá as funções de chamada TestContract.sol, enquanto o outro contrato, Person.sol, terá as funções que você chamará do contrato anterior, TestContract.sol.

O Contrato de Chamada Person

Navegue até a pasta de contratos em seu espaço de trabalho e renomeie o contrato existente de Lock.sol para Person.sol.

Para inicializar o contrato e as variáveis necessárias, copie e cole o código abaixo:


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

contract Person {

// Inicializa as variáveis como Null ou None

    string name;

    uint256 age;

    bool has_payed;

}

Enter fullscreen mode Exit fullscreen mode

Dentro do contrato Person.sol, você criará as seguintes funções simples:

  • A primeira função será uma função externa getDetails que modifica as variáveis públicas name e age. A função aceitará os detalhes de uma pessoa como inputs e os atribuirá às variáveis públicas.

Adicione a função getDetails abaixo ao contrato Person.sol criado anteriormente.


function getDetails(string memory _name, uint256 _age) external {

    name = _name;

    age = _age;

}

Enter fullscreen mode Exit fullscreen mode
  • A segunda função sayDetailstambém será uma função de visualização externa que simplesmente retorna os detalhes da Person mais recente armazenados na função getDetails.

Copie e adicione o código abaixo no contrato Person.sol como a próxima função.


function sayDetails() external view returns (string memory, uint256) {

    return (name, age);

}

Enter fullscreen mode Exit fullscreen mode
  • A terceira função, payFee, será uma função de pagamento externo que transfere dinheiro para o contrato para simular uma pessoa fazendo um pagamento. A função define a variável booleana is_payed como true (verdadeira) e a variável amount (valor pago) como msg.value.

Copie a função abaixo no contrato Person.sol.


function payFee() external payable {

    value = msg.value;

    has_payed = true;

}

Enter fullscreen mode Exit fullscreen mode
  • O último contrato é uma função de visualização externa que retorna múltiplas variáveis value, contract_balance, has_payed com base na função de pagamento payFee que foi chamada anteriormente.

function getValue() external view returns(uint256, uint256, bool) {

    return (value, address(this).balance, has_payed);

}

Enter fullscreen mode Exit fullscreen mode

As quatro funções criadas são funções de amostra para copiar um cenário real de chamada de diferentes tipos de funções de um contrato.

Nota: Como alternativa, ao criar chamadas de contrato, você pode usar a palavra-chave Interface para inicializar o contrato de chamada. Para saber mais sobre a palavra-chave Interface e outros tipos de dados básicos do Solidity, clique aqui.

Para fins de uniformidade, copie e cole todo o código abaixo no arquivo de contrato Person.sol.


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract Person {

    string name;

    uint256 age;

    bool has_payed;

    uint256 value;

    function sayDetails() external view returns (string memory, uint256) {

        return (name, age);

    }

    function getDetails(string memory _name, uint256 _age) external {

        name = _name;

        age = _age;

    }

    function payFee() external payable {

        value = msg.value;

        has_payed = true;

    }

    function getValue() external view returns(uint256, uint256, bool) {

        return (value, address(this).balance, has_payed);

    }

}

Enter fullscreen mode Exit fullscreen mode

O contrato Chamador TestContract

O segundo contrato, TestContract.sol, será o contrato de teste que fará as chamadas de contrato para o contrato Person.sol.

O contrato também terá quatro funções diferentes para chamar as quatro funções diferentes do primeiro contrato, Person.sol.

Quando você quiser chamar contratos de outros contratos, um dos inputs deverá ser o endereço do contrato que você está chamando e seguir o formato abaixo:


function <function_name> <(function_inputs)> <visibility> <mutability> returns(output_datatype) {

    do something

    return something

}
Enter fullscreen mode Exit fullscreen mode

Nota: Não copie a função acima, pois ela é apenas um layout de como estruturar uma função de chamada.

Para inicializar o contrato TestContract.sol, copie o código abaixo:


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import './Person.sol';

contract TestContract {

}

Enter fullscreen mode Exit fullscreen mode

***Nota: Você precisará importar o contrato Person.sol para fazer referência às funções no contrato Person.sol que você chamará.

  • A primeira função, callGetDetails, aceita o endereço do contrato Person.sol implantado como _test e os outros argumentos _name e _age para passar para a função getDetails no contrato Person.sol.

Copie e adicione a função abaixo ao contrato:


function callGetDetails(address _test, string memory _name, uint256 _age) external {

    Person(_test).getDetails(_name, _age);

}

Enter fullscreen mode Exit fullscreen mode
  • A segunda função, callSayDetails, será uma função de visualização externa que recebe o endereço do contrato Person.sol implantado como _test. E retorna as variáveis de nome e idade na função SayDetails do contrato Person.sol.

Copie e adicione a função abaixo ao contrato:


function callSayDetails(address _test) external view returns (string memory, uint256) {

    return Person(_test).sayDetails();

}

Enter fullscreen mode Exit fullscreen mode
  • A terceira função callpayFee chamará a função payFee no contrato Person.sol. Ela é uma função de pagamento para enviar ETH para o contrato inteligente.

function callpayFee(address _test) external payable {

    paying(_test).payFee();

}

Enter fullscreen mode Exit fullscreen mode
  • A última função callgetValue será chamada de getValue do contrato anterior Person.sol. A função simplesmente retornará os mesmos valores que a função getValue.

function callgetValue(address _test) external view returns(uint256, uint256, bool) {

    return paying(_test).getValue();

}

Enter fullscreen mode Exit fullscreen mode

Copie e adicione o código abaixo:


function callgetValue(address _test) external view returns(uint256, uint256, bool) {

    return paying(_test).getValue();

}

Enter fullscreen mode Exit fullscreen mode

Depois de adicionar todas as funções criadas acima, seu contrato TestContract.sol completo deverá ser exatamente como o código abaixo.


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import './Person.sol';

contract TestContract{

    function callGetDetails(address _test, string memory _name, uint256 _age) external {

        Person(_test).getDetails(_name, _age);

    }

    function callSayDetails(address _test) external view returns (string memory, uint256) {

        return Person(_test).sayDetails();

    }

    function callpayFee(address _test) external payable {

        Person(_test).payFee();

    }

    function callgetValue(address _test) external view returns(uint256, uint256, bool) {

        return Person(_test).getValue();

    }

}

Enter fullscreen mode Exit fullscreen mode

Em seguida, você implantará os contratos que criou na Blockchain Celo.

Implantação do Alfajores da Celo

Esperamos que você esteja familiarizado com a implantação de um contrato na Blockchain Celo. Caso contrário, aqui está um guia rápido sobre a implantação na Blockchain Celo.

Nas próximas etapas, você implantará os dois contratos criados anteriormente na blockchain Celo para começar a fazer as chamadas de contrato.

  1. Para compilar os contratos, execute o comando npm hardhat compile em seu terminal.
  2. Vá até a pasta de implantação e substitua o script de implantação Lock.js por outros dois scripts de implantação. Renomeie os arquivos com deploy_TestContract.js e deploy_PersonContract.js.
  3. Copie e cole o código abaixo no arquivo deploy_PersonContract.js:

const hre = require("hardhat");

const main = async () => {

  const PersonContract = await hre.ethers.getContractFactory("Person");

  const Person = await PersonContract.deploy();

  await Person.deployed();

  console.log("The Person contract was deployed to: ", Person.address);

};

const runMain = async () => {

  try {

    await main();

    process.exit(0);

  } catch (error) {

    console.error(error);

    process.exit(1);

  }

};

runMain();

Enter fullscreen mode Exit fullscreen mode
  1. Copie e cole o código abaixo no arquivo deploy_TestContract.js:

const hre = require("hardhat");

const main = async () => {

  const TestContract = await hre.ethers.getContractFactory("TestContract");

  const TestingContractCalls = await TestContract.deploy();

  await TestingContractCalls.deployed();

  console.log(

    "The TestContractCall contract was deployed to: ",

    TestingContractCalls.address

  );

}

const runMain = async () => {

  try {

    await main();

    process.exit(0);

  } catch (error) {

    console.error(error);

    process.exit(1);

  }

}

runMain();

Enter fullscreen mode Exit fullscreen mode
  1. Em seguida, vá até o arquivo hardhat.config.js na pasta raiz e substitua o código de configuração do Hardhat pelo código de configuração da Celo aqui.
  2. Substitua a versão do Solidity especificada na parte inferior do arquivo hardhat.config.js pela mesma versão do Solidity especificada em seus contratos.
  3. Execute o comando npm i dotenv para fazer download da dependência dotenv e crie um novo arquivo na pasta raiz .env.
  4. Crie uma variável com o nome MNEMONIC dentro do arquivo dotenv e adicione os MNEMONICs da carteira desejada como valor.

Nota: Os MNEMONICs da sua carteira são simplesmente a frase de recuperação usada na criação da sua carteira. Ainda não sabe o que são seus MNEMONICs? Aqui está uma leitura rápida.

Certifique-se de que o arquivo .env seja adicionado ao seu arquivo .gitignore se for fazer push para qualquer controle de versão.

  1. Finalmente, execute o seguinte comando para implantar os dois contratos:
  2. Execute o comando npx hardhat run scripts/deploy_PersonContract.js --network alfajores para implantar o contrato Person.sol.

Nota: Certifique-se de copiar o endereço do contrato que aparece no console; você precisará dele ao fazer as chamadas do contrato.

  • Execute o comando npx hardhat run scripts/deploy_TestContract.js --network alfajores para implantar o contrato TestContract.sol.

Nota: Certifique-se de copiar o endereço do contrato que aparece no console; você precisará dele ao fazer as chamadas do contrato.

Voila, Contratos Implantados…

Realização de Chamadas de Contrato

Agora é hora de fazer as chamadas de contrato.

Você usará a ferramenta integrada do Hardhat, o Hardhat Console, para interagir com os contratos na blockchain e fazer as chamadas de contrato.

  • Execute o comando npx hardhat console --network alfajores para ativar o console do Hardhat. Você notará que uma seta de prompt será exibida >.
  • Primeiramente, você terá que testar as funções no contrato Person.sol chamando as funções.
  • Para começar, execute o código const Person = await ethers.getContractFactory("Person"), para obter a fábrica de contrato implantada.
  • Em seguida, execute o comando const person = await Person.attach("<Person.sol_contract_address>"), para obter acesso ao contrato na blockchain.

Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

Agora, para chamar as funções no contrato Person.sol:

  • Execute o comando await person.sayDetails(), que retorna as variáveis vazias name e age. Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

Image description

  • Execute o comando await person.getDetails("Albert", 22). Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

  • Execute novamente o primeiro comando await person.sayDetails(); isso deve retornar o nome e o input de valores que você enviou anteriormente. Albert e 22. Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

  • Execute o comando await person.payFee(). Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

  • Execute o comando await person.getValue(). Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

  • Agora que você sabe o que as funções do contrato Person.sol fazem, é hora de tentar chamar a mesma função de outro contrato implantado TestContract.sol.
  • Para começar, execute o código const TestContract = await ethers.getContractFactory("TestContract"), para simplesmente obter a fábrica de contrato implantada.
  • Em seguida, execute o comando const test = await TestContract.attach("<TestContract.sol_contract_address>"), para obter acesso ao contrato na blockchain:

Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

Nota: É aqui que você precisará do endereço do contrato da Person.sol. Você precisará passar o endereço como o primeiro argumento para todas as chamadas de função.

Supondo que o endereço do contrato Person.sol implantado seja: 0xA019Ad7Ed1F3fc0276E0854F2fF022EFeFf5C8e1

  • Execute o comando await test.callGetDetails("0xA019Ad7Ed1F3fc0276E0854F2fF022EFeFf5C8e1", "Julia", 25). Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

Execute o comando `await test.callSayDetails("0xA019Ad7Ed1F3fc0276E0854F2fF022EFeFf5C8e1"). Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

  • Execute o comando await test.callpayFee("0xA019Ad7Ed1F3fc0276E0854F2fF022EFeFf5C8e1"). Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

  • Execute o comando await test.callgetValue("0xA019Ad7Ed1F3fc0276E0854F2fF022EFeFf5C8e1"). Uma transação bem-sucedida deve se parecer com a imagem abaixo:

Image description

Conclusão

Finálè, você concluiu e aprendeu muitas coisas novas aqui. Você criou dois contratos inteligentes, um para chamar funções e o outro para fazer chamadas de contrato na blockchain; você implantou os dois contratos na Blockchain Celo com sucesso. Você também interagiu com o contrato implantado usando o Console Hardhat e fez várias chamadas de contrato na Blockchain Celo.

Parabéns por ter dado mais um grande passo na toca de coelho da Web3.

Próximos Passos

Você também pode ler sobre como executar o teste de unidade para contratos inteligentes usando o Truffle e como executar o teste de unidade para contratos inteligentes usando o Hardhat.

Aqui estão alguns outros artigos tutoriais que podem lhe interessar.

Sobre o Autor

Mayowa Julius Ogungbola

Engenheiro de software e redator técnico sempre disposto a trabalhar com novas ideias. Gosto de trabalhar no GitHub. Você também pode descobrir sobre o que eu tuíto e se conectar comigo no Twitter.

Referências

Aqui está um link para o código de amostra do tutorial completo no meu GitHub. Deixe uma
estrela no repositório se achar útil.

Esse artigo foi escrito por Phenzic e traduzido por Fátima Lima. o original pode ser lido aqui.

Latest comments (0)