Lição: 030: Testes e Depuração de Programas Solana
Nesta aula, vamos explorar como testar e depurar efetivamente programas Solana escritos em Rust. Os testes são uma parte crítica do processo de desenvolvimento, garantindo que seu programa funcione como pretendido e se comporte corretamente sob diversas condições. Vamos abordar tanto testes unitários quanto testes de integração, além de discutir técnicas e ferramentas de depuração disponíveis no ecossistema Solana.
Configurando Seu Ambiente
Antes de começarmos a escrever testes, certifique-se de que você tenha um ambiente de desenvolvimento Solana configurado. Você deve ter o seguinte:
- Rust instalado (use
rustup
) - Solana CLI para interagir com a blockchain
- Node.js e npm para dependências do framework de testes
Certifique-se de que seu Solana CLI está configurado para o devnet:
solana config set --url devnet
Escrevendo Testes Unitários
Os testes unitários em Rust podem ser definidos no mesmo arquivo que o código do seu programa. Você pode aproveitar o framework de testes embutido do Rust para criar e executar seus testes.
Aqui está um exemplo simples de um programa Solana com testes unitários. Vamos criar um programa que incrementa um número armazenado em uma conta:
Passo 1: Crie Seu Programa
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWxTWqDkWvSmtWvLp9mcGkKAcXes");
#[program]
pub mod contador {
use super::*;
pub fn inicializar(ctx: Context<Inicializar>) -> ProgramResult {
let conta = &mut ctx.accounts.conta_contador;
conta.contador = 0;
Ok(())
}
pub fn incrementar(ctx: Context>Incrementar>) -> ProgramResult {
let conta = &mut ctx.accounts.conta_contador;
conta.contador += 1;
Ok(())
}
}
#[derive(Accounts)]
pub struct Inicializar<'info> {
#[account(init, payer = usuario, space = 8 + 8)]
pub conta_contador: Account<'info, ContaContador>,
#[account(mut)]
pub usuario: Signer<'info>,
pub sistema_programa: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Incrementar<'info> {
#[account(mut)]
pub conta_contador: Account<'info, ContaContador>,
}
#[account]
pub struct ContaContador {
pub contador: u64,
}
Passo 2: Escreva Testes Unitários
Agora, podemos criar um módulo de teste na parte inferior do mesmo arquivo. Este módulo incluirá testes para as funções inicializar
e incrementar
.
#[cfg(test)]
mod testes {
use super::*;
use anchor_lang::prelude::*;
use anchor_lang::solana_program::program::invoke_signed;
use solana_program_test::*;
#[tokio::test]
async fn teste_inicializar() {
let mut teste_programa = ProgramTest::new(
"contador",
id(),
processor!(process_instruction),
);
let (mut cliente_bancos, pagador, hash_ultimo_bloco) = teste_programa.start().await;
let conta_contador = Keypair::new();
// Inicializa a conta contador
let tx = Transaction::new_signed_with_payer(
&[instruction::inicializar(
accounts::Inicializar {
conta_contador: conta_contador.pubkey(),
usuario: pagador.pubkey(),
sistema_programa: system_program::id(),
},
)],
Some(&pagador.pubkey()),
&[&pagador, &conta_contador],
hash_ultimo_bloco,
);
// Envia a transação
cliente_bancos.process_transaction(tx).await.unwrap();
// Verifica a inicialização
let dados_conta = cliente_bancos
.get_account(conta_contador.pubkey())
.await
.unwrap()
.unwrap();
let conta_contador: ContaContador = try_from_slice(&dados_conta.data).unwrap();
assert_eq!(conta_contador.contador, 0);
}
#[tokio::test]
async fn teste_incrementar() {
let mut teste_programa = ProgramTest::new(
"contador",
id(),
processor!(process_instruction),
);
let (mut cliente_bancos, pagador, hash_ultimo_bloco) = teste_programa.start().await;
let conta_contador = Keypair::new();
// Inicializa a conta contador
let tx = Transaction::new_signed_with_payer(
&[instruction::inicializar(
accounts::Inicializar {
conta_contador: conta_contador.pubkey(),
usuario: pagador.pubkey(),
sistema_programa: system_program::id(),
},
)],
Some(&pagador.pubkey()),
&[&pagador, &conta_contador],
hash_ultimo_bloco,
);
cliente_bancos.process_transaction(tx).await.unwrap();
// Incrementa o contador
let tx = Transaction::new_signed_with_payer(
&[instruction::incrementar(accounts::Incrementar {
conta_contador: conta_contador.pubkey(),
})],
Some(&pagador.pubkey()),
&[&pagador, &conta_contador],
hash_ultimo_bloco,
);
cliente_bancos.process_transaction(tx).await.unwrap();
// Verifica o incremento
let dados_conta = cliente_bancos
.get_account(conta_contador.pubkey())
.await
.unwrap()
.unwrap();
let conta_contador: ContaContador = try_from_slice(&dados_conta.data).unwrap();
assert_eq!(conta_contador.contador, 1);
}
}
Executando Testes
Para executar seus testes, simplesmente execute o seguinte comando no seu terminal:
cargo test
Esse comando compilará seu programa e executará todos os testes definidos no arquivo do seu programa.
Depurando Seus Programas Solana
Depurar programas Solana pode ser desafiador devido à sua natureza de execução em um ambiente distribuído. No entanto, aqui estão algumas estratégias e ferramentas que você pode usar para depuração:
1. Registro de Log
Use logs para obter insights sobre o fluxo de execução e o estado do seu programa. Em Rust, você pode usar o macro msg!
para imprimir mensagens nos logs do programa:
msg!("Valor do contador antes do incremento: {}", conta.contador);
2. Testando em um Ambiente Local
O framework de teste de programas Solana cria um validador de teste local que simula a rede Solana. Você pode usar esse ambiente local para testar mudanças rapidamente. Inicie o validador de teste local em outra janela do terminal:
solana-test-validator
3. Solana Explorer
Após implantar seu programa em um cluster, use o Solana Explorer para visualizar detalhes e logs das transações. Esta ferramenta fornece uma interface gráfica para explorar transações, estados de conta e logs de eventos.
4. Ferramentas de Depuração
Utilize ferramentas de depuração do Rust:
- Cargo: Você pode executar seus testes com a opção
-- --nocapture
para ver logs no terminal. - GDB: Use o GDB para depurar binários Rust, mas isso requer configuração adicional e pode ser complexo para iniciantes.
Conclusão
Os testes e a depuração são vitais para desenvolver programas Solana confiáveis. Nesta aula, cobrimos como estruturar seus testes, escrever testes unitários para seus programas Solana e utilizar métodos de depuração. Continue praticando e refinando suas habilidades, e você se tornará proficiente em desenvolver aplicações sólidas na Solana!