Как тестировать абстрактные классы на C ++ с помощью Google Test framework? - PullRequest
2 голосов
/ 06 мая 2020

Я использую структуру Google Test для написания модульных тестов для кода C ++. Среди других тестов я хочу проверить правильность построения объектов разных классов, которые все являются производными от одного абстрактного класса. Начнем с абстрактного класса:

class AbstractClass
{
    public:
        virtual ~AbstractClass() = default;
        std::string getName() const { return name_; }
        std::string toString() const { return toStringImpl(); }

    protected:
        AbstractClass(std::string name) : name_(name) {}

    private:
        virtual std::string toStringImpl() const = 0;
        std::string name_;
};

Он имеет функцию getName(), которая реализуется самим абстрактным классом. И у него есть функция toString(), реализация которой делегируется производным классам частной чистой виртуальной функцией toStringImpl(). toString() здесь не представляет особого интереса, но его концепция делает этот класс абстрактным.

У меня есть два производных класса conctrete, а именно:

class ConcreteClassA : public AbstractClass
{
    public:
        ConcreteClassA(std::string name) : AbstractClass(name) {}
    private:
        virtual std::string toStringImpl() const override { return ""; }
};

class ConcreteClassB : public AbstractClass
{
    public:
        ConcreteClassB(std::string name) : AbstractClass(name) {}
    private:
        virtual std::string toStringImpl() const override { return ""; }
};

Ничего особенного, просто тот факт, что конструктор абстрактного класса вызывается во время построения этих конкретных классов.

Если я хочу проверить правильность конструкции, я, конечно, могу написать все тесты для всех производных классов, как в следующем примере, где я включаю тесты для функциональности абстрактного класса:

class ConcreteClassATests : public ::testing::Test
{};

TEST_F(ConcreteClassATests, constructionSuccessful)
{
    ConcreteClassA a {"TestA"};
    ASSERT_EQ(a.getName(), "TestA");
}

class ConcreteClassBTests : public ::testing::Test
{};

TEST_F(ConcreteClassBTests, constructionSuccessful)
{
    ConcreteClassB b {"TestB"};
    ASSERT_EQ(b.getName(), "TestB");
}

Учитывая m производные классы и n тесты для содержимого абстрактного класса, это приведет к m * п рукописных тестов. Я думаю, что это должно быть решено с помощью n рукописных тестов (в результате получаются n или m * n выполненные тесты).

Я уже читал около абстрактных тестов с параметризацией значений , которые звучат многообещающе, а также примерно типизированных тестов , но похоже, что это применимо только к функциям тестирования, которые получают ввод и выводят результат. Я не уверен, можно ли применить эти концепции для проверки правильности построения объектов.

Итак, может ли кто-нибудь сказать мне, можно ли каким-то образом определить тест для «абстрактной функции» только один раз?


Чтобы воспроизвести и запустить мой пример, все фрагменты можно объединить в один исходный файл. Просто добавьте следующие две строки вверху и сделайте ссылку на gmock_main и pthread:

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