Testes em C++: Testes Unitários, de Integração e E2E com exemplos

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

Introdução: Por que os testes são criticamente importantes para projetos C++



Testar código C++ não é apenas uma formalidade, mas uma prática fundamental que garante a estabilidade, segurança e capacidade de manutenção do software. Diferente de linguagens interpretadas, onde um erro pode se manifestar instantaneamente, em C++ os bugs frequentemente permanecem ocultos até o momento da compilação ou execução em condições específicas. Um vazamento de memória perdido, comportamento indefinido ou manipulação incorreta de ponteiros podem levar a falhas fatais.



A indústria moderna de desenvolvimento destaca três níveis principais de teste: Unit (unitário), Integration (integração) e E2E (ponta a ponta). Cada um resolve seu próprio problema e juntos formam a "pirâmide de testes", permitindo capturar até 90% dos erros antes da entrada em produção.



Neste artigo, analisaremos cada tipo de teste com exemplos práticos em C++, usando os frameworks populares Google Test e Catch2, além de discutir as melhores práticas para sua aplicação.



1. Teste Unitário: Verificação de módulos atômicos



Testes unitários são o nível mais baixo e mais rápido. Eles verificam funções, classes ou métodos individuais isolados do resto do sistema. O objetivo é garantir que cada "bloco de construção" do código funcione corretamente.



Exemplo de Teste Unitário com Google Test



Considere uma função matemática simples:



// math_utils.h#pragma once

namespace MathUtils { int add(int a, int b); int divide(int a, int b);}


// math_utils.cpp#include "math_utils.h"

namespace MathUtils { int add(int a, int b) { return a + b; }

int divide(int a, int b) { if (b == 0) { throw std::invalid_argument("Division by zero"); } return a / b; }}


Agora vamos escrever testes unitários usando Google Test:



// test_math_utils.cpp#include <gtest/gtest.h>#include "math_utils.h"

TEST(MathUtilsTest, AddPositiveNumbers) { EXPECT_EQ(MathUtils::add(2, 3), 5); EXPECT_EQ(MathUtils::add(0, 0), 0);}

TEST(MathUtilsTest, AddNegativeNumbers) { EXPECT_EQ(MathUtils::add(-1, -1), -2); EXPECT_EQ(MathUtils::add(-5, 3), -2);}

TEST(MathUtilsTest, DivideNormal) { EXPECT_EQ(MathUtils::divide(10, 2), 5); EXPECT_EQ(MathUtils::divide(7, 3), 2); // Divisão inteira}

TEST(MathUtilsTest, DivideByZeroThrows) { EXPECT_THROW(MathUtils::divide(5, 0), std::invalid_argument);}


Uso de Mock Objects



Para isolar um módulo, muitas vezes é necessário substituir dependências. Google Mock (parte do Google Test) permite criar stubs:



// database_interface.hclass DatabaseInterface {public:    virtual ~DatabaseInterface() = default;    virtual bool save(const std::string& data) = 0;};

// user_service.cppclass UserService { DatabaseInterface& db;public: explicit UserService(DatabaseInterface& db) : db(db) {} bool registerUser(const std::string& name) { return db.save("user:" + name); }};

// test_user_service.cpp#include <gmock/gmock.h>

class MockDatabase : public DatabaseInterface {public: MOCK_METHOD(bool, save, (const std::string&), (override));};

TEST(UserServiceTest, RegisterUserCallsDb) { MockDatabase mockDb; EXPECT_CALL(mockDb, save("user:Alice")).WillOnce(testing::Return(true));

UserService service(mockDb); EXPECT_TRUE(service.registerUser("Alice"));}


Vantagens: Velocidade de execução (milissegundos), localização precisa de erros, possibilidade de executar sem dependências externas.
Desvantagens: Não verificam a interação entre componentes reais.



2. Teste de Integração: Verificação da combinação de componentes



Testes de integração verificam como vários mo

Blogs

Book Recommendations