Testes em Rust: unit, integration, e2e — guia completo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course
```html

Introdução: Por que testar em Rust é simples e confiável

Rust foi projetado desde o início como uma linguagem que ajuda a escrever código seguro e confiável. No entanto, mesmo o sistema de tipos mais rigoroso não garante a correção da lógica de negócios. É aqui que os testes entram em ação. Em Rust, o processo de escrever testes está integrado diretamente na ferramenta cargo, tornando-o incrivelmente conveniente e acessível.

Neste artigo, abordaremos três níveis de teste: unit (unitário), integration (integração) e e2e (end-to-end). Você aprenderá como escrever testes, quando usar cada abordagem e como automatizar a verificação do seu código. O material será útil tanto para iniciantes quanto para desenvolvedores experientes que estão migrando para Rust.

Testes unitários: Testando por dentro

Testes unitários são o tipo mais básico e comum de teste. Eles verificam funções, métodos ou módulos individuais isolados do resto do sistema. Em Rust, é comum escrever testes unitários no mesmo arquivo que o código testado, ou em um arquivo separado tests.rs dentro do módulo.

Como escrever testes unitários em Rust

Para criar um teste, usa-se o atributo #[test]. Os testes são colocados em um módulo com o atributo #[cfg(test)], que garante que o código de teste não seja incluído na compilação final.

// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

pub fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err(String::from("Division by zero"))
    } else {
        Ok(a / b)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add() {
        assert_eq!(add(2, 3), 5);
    }

    #[test]
    fn test_add_negative() {
        assert_eq!(add(-1, 1), 0);
    }

    #[test]
    fn test_divide_success() {
        let result = divide(10.0, 2.0);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 5.0);
    }

    #[test]
    fn test_divide_by_zero() {
        let result = divide(10.0, 0.0);
        assert!(result.is_err());
        assert_eq!(result.unwrap_err(), "Division by zero");
    }
}

Executando testes unitários

Você pode executar os testes com um único comando:

cargo test

A saída mostrará quantos testes passaram e quantos falharam. Para executar um teste específico, use um filtro:

cargo test test_add

Testes unitários são ideais para verificar casos limite, tratamento de erros e a correção de algoritmos. Eles são rápidos e não requerem dependências externas.

Testes de integração: Verificando a interação entre módulos

Testes de integração verificam como diferentes módulos da sua biblioteca ou aplicação funcionam juntos. Ao contrário dos testes unitários, eles não têm acesso a funções internas (a menos que estejam exportadas como pub). Testes de integração são escritos em uma pasta separada tests/ no nível raiz do projeto.

Estrutura dos testes de integração

Crie uma pasta tests/ na raiz do seu projeto e adicione arquivos de teste nela. Cada arquivo será compilado como um crate separado.

// tests/integration_test.rs
use my_crate; // nome do seu crate

#[test]
fn test_add_integration() {
    assert_eq!(my_crate::add(10, 20), 30);
}

#[test]
fn test_divide_integration() {
    let result = my_crate::divide(100.0, 4.0);
    assert_eq!(result.unwrap(), 25.0);
}

Módulo comum para testes

Se vários testes de integração usam as mesmas funções auxiliares, coloque-as em um módulo comum. Para isso, crie a pasta tests/common/mod.rs:

// tests/common/mod.rs
pub fn setup() {
    // inicialização do logger, banco de dados, etc.
    println!("Setting up test environment...");
}

// tests/another_test.rs
mod common;

#[test]
fn test
```                

Blogs

Book Recommendations