Testes unitários
Testes unitários em C++ são métodos de validação de pequenos blocos de código, como funções ou classes, para garantir que funcionem corretamente de forma isolada. Eles são fundamentais para o desenvolvimento de softwares robustos, pois permitem identificar erros precocemente, facilitam a manutenção e aumentam a confiabilidade do sistema.
No desenvolvimento em C++, testes unitários devem ser aplicados desde a criação de novas funções até a refatoração de módulos existentes. Eles estão intimamente ligados aos princípios de programação orientada a objetos, ao uso eficiente de estruturas de dados e algoritmos, além de boas práticas de gerenciamento de memória. Este tutorial mostrará como implementar testes unitários básicos e avançados em C++, integrando-os de forma prática ao ciclo de desenvolvimento de software.
Ao concluir este conteúdo, você aprenderá a testar funções simples, validar comportamento de classes complexas, lidar com exceções, prevenir vazamentos de memória e seguir padrões de design que garantem código limpo e confiável. Testes unitários em C++ também facilitam a integração com frameworks de teste, automação de builds e metodologias como TDD (Test-Driven Development).
Exemplo Básico
text\#include <iostream>
\#include <vector>
\#include <cassert>
int somaVetor(const std::vector<int>& numeros) {
int soma = 0;
for (int num : numeros) {
soma += num;
}
return soma;
}
void testeSomaVetor() {
std::vector<int> teste1 {1, 2, 3, 4, 5};
assert(somaVetor(teste1) == 15);
std::vector<int> teste2 {-1, -2, -3};
assert(somaVetor(teste2) == -6);
std::vector<int> teste3 {};
assert(somaVetor(teste3) == 0);
std::cout << "Todos os testes básicos passaram!" << std::endl;
}
int main() {
testeSomaVetor();
return 0;
}
Neste exemplo, a função somaVetor
calcula a soma de todos os elementos de um vetor. A função de teste testeSomaVetor
verifica diferentes cenários: números positivos, negativos e vetor vazio. O uso de assert
garante que qualquer falha seja imediatamente sinalizada, interrompendo o programa.
A passagem do vetor por referência constante (const std::vector<int>&
) evita cópias desnecessárias, melhorando a performance. O loop baseado em range (for (int num : numeros)
) torna o código mais limpo e legível. Este padrão é adequado para testar funções de forma independente, promovendo modularidade e manutenibilidade do código.
Exemplo Prático
text\#include <iostream>
\#include <stdexcept>
\#include <cassert>
class ContaBancaria {
private:
std::string titular;
double saldo;
public:
ContaBancaria(const std::string& nome, double saldoInicial) : titular(nome), saldo(saldoInicial) {
if (saldoInicial < 0) throw std::invalid_argument("Saldo inicial não pode ser negativo");
}
void depositar(double valor) {
if (valor <= 0) throw std::invalid_argument("Valor de depósito deve ser positivo");
saldo += valor;
}
void sacar(double valor) {
if (valor > saldo) throw std::runtime_error("Saldo insuficiente");
saldo -= valor;
}
double obterSaldo() const { return saldo; }
};
void testeContaBancaria() {
ContaBancaria conta("Alice", 100.0);
conta.depositar(50.0);
assert(conta.obterSaldo() == 150.0);
conta.sacar(30.0);
assert(conta.obterSaldo() == 120.0);
try {
conta.sacar(200.0);
assert(false);
} catch (const std::runtime_error&) {
assert(true);
}
try {
ContaBancaria contaInvalida("Bob", -10.0);
assert(false);
} catch (const std::invalid_argument&) {
assert(true);
}
std::cout << "Todos os testes avançados passaram!" << std::endl;
}
int main() {
testeContaBancaria();
return 0;
}
Este exemplo testa a classe ContaBancaria
, cobrindo operações normais e tratamento de exceções. Blocos try-catch permitem verificar o comportamento correto frente a erros, garantindo que o código responda adequadamente. O uso de referências constantes, tratamento de exceções e asserts fortalece a robustez do código. Estes métodos são essenciais para a validação de módulos complexos em projetos reais e para manter a integridade das operações financeiras ou críticas de negócio.
Melhores práticas e armadilhas comuns em C++ para testes unitários:
- Utilizar referências constantes (
const &
) para evitar cópias desnecessárias. - Manter testes independentes e determinísticos.
- Testar valores limite e exceções.
- Usar smart pointers para prevenir vazamentos de memória.
-
Seguir convenções de nomenclatura e estilo consistentes.
Erros comuns: -
Uso de ponteiros crus em vez de smart pointers.
- Dependência entre testes.
- Algoritmos ineficientes em grandes volumes de dados.
- Ignorar tratamento de exceções.
- Misturar lógica de teste com código de produção.
📊 Tabela de Referência
C++ Element/Concept | Description | Usage Example |
---|---|---|
somaVetor função | Calcula a soma dos elementos de um vetor | int resultado = somaVetor({1,2,3}); |
assert macro | Verifica condições | assert(resultado == 6); |
ContaBancaria classe | Gerencia operações de conta | ContaBancaria conta("Alice", 100.0); |
try-catch bloco | Testa e manipula exceções | try { conta.sacar(200); } catch(...) {} |
const referência | Evita cópia e protege dados | void depositar(const double& valor); |
Testes unitários em C++ aumentam a confiabilidade e previsibilidade do código, permitindo que os desenvolvedores detectem falhas rapidamente, integrem TDD e automatizem a verificação de qualidade. Próximos passos recomendados incluem aprender frameworks de teste como Google Test ou Catch2, integrar testes ao processo de build e validar módulos em sistemas maiores, garantindo que cada componente funcione isoladamente e em conjunto.
🧠 Teste Seu Conhecimento
Teste Seu Conhecimento
Desafie-se com este questionário interativo e veja o quão bem você entende o tópico
📝 Instruções
- Leia cada pergunta cuidadosamente
- Selecione a melhor resposta para cada pergunta
- Você pode refazer o quiz quantas vezes quiser
- Seu progresso será mostrado no topo