Макет для конкретного класса с использованием gmock в C ++ - PullRequest
2 голосов
/ 30 апреля 2020

Я застрял в создании макета для конкретного класса .

Я знаю, что это не очень хорошая идея, но Мне не разрешено менять производственный код .

Мой код похож на:

Class A
{
public:
        A(B* b)
        {
                this->b = b;
        }
.........................
 void function_from_a_to_test(<arg>)
{
        if(!b)
                b->function_from_b();
        else
             //something to do
}
private:
        B * b;
};

class B
{
........
 public:       
        void function_from_b();
......
};
class MockB : public B , testing::Mock //i don't know why I can that, B is not virtual 
{

 MOCK_METHOD(function_from_b, void, (void));

};


A_Test :testing::Test{
 SetUp()
{
        b = new B();
        a = new A(b);
}

 TearDown()
{
        delete b ;
        delete a ;
}

void set_b(B * bb)
{
        a->b = bb;
}

.........................
}

In order to test I used Test_f

TEST_F(A_Test, Test_function_from_a_to_test)
{
//arrange

//act
 B * b_t = new MockB();
set_b(b_t);
EXPECT_CALL(*(static_cast<MockB> b_t), function_from_b))
        .Times(10);

function_from_a_to_test(arg);
}

Кажется, что тест пройден , но я получил утечка памяти при обработке c приведение.

И если я сохраню результат приведения к преобразованию c в другую переменную (чтобы удалить его), ожидаемый вызов с этой переменной будет с ошибкой .

Я знаю, что это не очень хорошая практика, но я не могу изменить производственный код.

У кого-нибудь есть идеи, как это решить? Или лучший способ проверить это?

1 Ответ

1 голос
/ 01 мая 2020

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

Если честно, я понятия не имею, каков результат этого static_cast, но, вероятно, это не хорошо.

Единственное Я могу думать о том, чтобы сделать то, что вы хотите сделать без изменения производственного кода , - это использовать другой путь включения в вашем тестовом проекте, который позволил бы полностью заменить бетон class B на макет class B. Это может или не может быть возможным, в зависимости от того, как структурирован ваш производственный код.

Если вам посчастливилось определить class B в отдельном заголовочном файле, то это просто: создайте фиктивный заголовочный файл с тем же именем, но другой папкой, и убедитесь, что папка отображается в пути включения перед расположением файла заголовка производства.

Файл B.h производства (в исходном местоположении и без изменений):

class B
{
public:
    void function_from_b() {}
};

Файл B.h (в месте расположения тестового кода):

class B
{
public:
    MOCK_METHOD(void, function_from_b, ());
};

Где-то в рабочем коде (без изменений):

#include "B.h" // Will load original or mock depending on include path

class A
{
public:
    A(B *b)
    {
        m_b = b;
    }

    void function_from_a_to_test(int arg)
    {
        if (m_b)
            m_b->function_from_b();
        else
            ;    //something to do
    }

private:
    B *m_b;
}

Код теста:

TEST(A_Test, Test_function_from_a_to_test)
{
    B b;
    A a(&b);

    EXPECT_CALL(b, function_from_b)
        .Times(1);

    a.function_from_a_to_test(0);
}
...