Testes em C++: unit, integration, e2e — nível avançado

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

Testes avançados em C++: de testes unitários a end-to-end

No desenvolvimento moderno em C++, a qualidade do código é determinada não apenas pelo seu desempenho, mas também pela sua confiabilidade. Os testes avançados vão muito além de verificações simples — é uma abordagem arquitetural que inclui testes unitários, de integração e end-to-end (e2e). Neste artigo, vamos analisar como construir corretamente a pirâmide de testes para projetos C++, usando Google Test, Google Mock e frameworks próprios.



1. Testes unitários: isolamento e mocks

Os testes unitários verificam módulos individuais (funções, classes) de forma isolada. Em nível avançado, a tarefa principal é aprender a criar mocks corretamente para as dependências. Vejamos um exemplo usando Google Mock.



Suponha que temos uma classe DatabaseConnector que depende de uma API externa. Queremos testar a lógica de processamento de dados sem acessar o banco de dados real.



#include <gmock/gmock.h>#include <gtest/gtest.h>

class DatabaseInterface {public: virtual ~DatabaseInterface() = default; virtual std::string fetchData(int id) = 0;};

class MockDatabase : public DatabaseInterface {public: MOCK_METHOD(std::string, fetchData, (int id), (override));};

class DataProcessor { DatabaseInterface& db;public: explicit DataProcessor(DatabaseInterface& db) : db(db) {} std::string process(int id) { auto raw = db.fetchData(id); if (raw.empty()) return "EMPTY"; return "PROCESSED: " + raw; }};

TEST(DataProcessorTest, ProcessWithValidData) { MockDatabase mockDb; EXPECT_CALL(mockDb, fetchData(42)) .WillOnce(testing::Return("Hello")); DataProcessor processor(mockDb); EXPECT_EQ(processor.process(42), "PROCESSED: Hello");}


O uso de MOCK_METHOD permite controlar com precisão o comportamento das dependências. É importante lembrar dos strict mocks (através de NiceMock ou StrictMock) para capturar chamadas inesperadas.



2. Testes de integração: testando interações

Os testes de integração verificam como os módulos funcionam juntos. Em C++, isso geralmente envolve testar a interação com o sistema de arquivos, protocolos de rede ou bancos de dados. Uma abordagem avançada é usar test fixtures e parameterized tests.



Exemplo: testando a classe FileManager, que lê e escreve em arquivos. Usamos diretórios temporários.



class FileManagerTest : public ::testing::Test {protected:    std::filesystem::path tempDir;    void SetUp() override {        tempDir = std::filesystem::temp_directory_path() / "test_files";        std::filesystem::create_directories(tempDir);    }    void TearDown() override {        std::filesystem::remove_all(tempDir);    }};

TEST_F(FileManagerTest, WriteAndReadFile) { FileManager fm(tempDir.string()); fm.write("test.txt", "data"); auto content = fm.read("test.txt"); EXPECT_EQ(content, "data");}


Para testes parametrizados, usamos TEST_P com INSTANTIATE_TEST_SUITE_P. Isso permite executar o mesmo teste com diferentes dados de entrada.



class MathTest : public ::testing::TestWithParam<std::tuple<int, int, int>> {};TEST_P(MathTest, Add) {    auto [a, b, expected] = GetParam();    EXPECT_EQ(add(a, b), expected);}INSTANTIATE_TEST_SUITE_P(AddTests, MathTest,    ::testing::Values(        std::make_tuple(1, 1, 2),        std::make_tuple(-1, 1, 0),        std::make_tuple(0, 0, 0)    ));


3. Testes End-to-End: verificando o ciclo completo

Os testes e2e simulam o comportamento do usuário final. Para aplicações C++, isso pode significar executar o binário completo, verificar sua saída ou interagir através de APIs. Nível avançado

Blogs

Book Recommendations