Методы базового класса GMOCK в производном классе

У меня есть класс, унаследованный от другого класса, как указано ниже:

class A
{
public:
    virtual void Show(){}
};

class B : public A
public:
    void BMethod1(){Show()}
};

Теперь я пишу тестовые примеры для класса B, поэтому я издевался над классом A:

class MockA : public A
{
    MOCK_METHOD0(Show, void());
};

Ниже приведен мой тестовый пример Google Test framework:

TEST(BTEST , ShowMethod)
{
    B bobj;
    MockA aobj;
    EXPECT_CALL(aobj , Show());
    bobj.BMethod1(); // updated as from bobj.METHOD0()
}

Но тестовые примеры вызывают реальную реализацию A::Show() - как в таком случае вызвать Mocked-версию MockA::Show()?

====================ОБНОВЛЕНИЕ============================= ====

Ну, приведенная ниже реализация помогла мне:

class A
{
public:
    virtual void Show(){}
};

class B : public A
public:
    void BMethod1(){Show()}
};

class BMock : public B
{
public:
   MOCK_METHOD0(Show, void());
};

Теперь используйте объект BMock для проверки необходимых методов класса B.


person Programmer    schedule 02.12.2017    source источник
comment
Вам разрешено изменять class B?   -  person user0042    schedule 02.12.2017
comment
Я могу, если это решит проблему, а также хотел бы проверить, существует ли какой-либо другой механизм.   -  person Programmer    schedule 02.12.2017


Ответы (4)


Вы должны сделать Show() виртуальным, чтобы получить MockA::Show() вместо A::Show().

person Nayfe    schedule 02.12.2017
comment
Я пробовал это, но все еще та же проблема - не могли бы вы подробно описать реализацию метода - person Programmer; 02.12.2017
comment
Будьте осторожны, чтобы поместить ключевое слово public в класс MockA. - person Nayfe; 02.12.2017
comment
что-то вроде этого ? class A { public: virtual void Show(){} }; class MockA : public A { public: MOCK_METHOD0(Show, void()); }; - person Nayfe; 02.12.2017
comment
@Nayfe Ваш ответ на самом деле не решает проблему ОП, но констатирует необходимый факт, позволяющий MockA переопределить эту функцию. - person user0042; 02.12.2017

Прежде всего:

    bobj.METHOD0();

совершенно неправильно. METHOD0 не является допустимым символом для доступа к имитируемой функции.

Вы хотите проверить, что B::BMethod1() вызывает A::Show(), верно?
Измените эту строку на

    bobj.BMethod1();

Вы можете изменить класс B, чтобы использовать его реализацию базового класса в качестве параметра шаблона:

class A
{
public:
    virtual void Show(){}
 // ^^^^^^^ See note 1
};

template<class Base>
class B : public Base
public:
    void BMethod1(){Show()}
};

Затем вы используете

B<A> bobj;
bobj.BMethod1();

в вашем производственном коде и

B<MockA> bobj;
EXPECT_CALL(bobj , Show());
bobj.BMethod1(); // <<< trigger the expectation

в коде вашего модульного теста.


В качестве бокового узла:

Это хорошо известный шаблон для внедрения базовых классов через параметры типа шаблона, называемые Mixin.
Хотя Mixins в основном предназначены для предоставления кусочных реализаций интерфейсов, которые в основном предназначены для составления общедоступных реализаций интерфейса.

Однако попадание в такой случай при попытке модульного тестирования класса в отношении этих манер автоматически привело бы меня к вопросу, есть ли у меня недостаток дизайна:

Является ли B действительно A или он скорее предназначен для использования экземпляра A в качестве переменной-члена, находящейся в собственности или на которую ссылаются?

Если мне понадобится проверить это в модульном тесте, я бы подумал о рефакторинге класса B во что-то вроде

class B {
    A& a_;
public:
    B(A& a) a_(a) {}
    void BMethod1() { a_.Show(); }
};

И соответствующим образом адаптируйте тестовые сценарии:

TEST(BTEST , ShowMethod)
{
    MockA aobj;
    B bobj(aobj);
    EXPECT_CALL(aobj , Show());
    bobj.BMethod1();
}

Что касается вашего комментария

Цель состоит в том, чтобы тестовый пример мог возвращать имитированные значения - EXPECT_CALL(mMockA, show()) .WillOnce(Return(false));

Это должно работать с примером выше:

EXPECT_CALL(bobj, Show()) .WillOnce(Return(false));

Но требует, чтобы Show() было объявлено как

virtual bool Show();

в классе A и т.п.

MOCK_METHOD0(Show, bool());

в MockA классе.


1)Объявление virtual необходимо, чтобы позволить MockA переопределить исходную реализацию.

person user0042    schedule 02.12.2017
comment
Методы A имеют виртуальную декларацию. Класс B создан из A. Спасибо, но как теперь я могу написать в своем тестовом примере, что ожидается вызов MocakA Show - например, EXPECT_CALL(mMockA, show()), где B создается как B‹MockA› - где MockA является класс, а mMockA — объект типа MockA. Я имею в виду, как мы можем написать EXPECT_CALL для метода MockA в моих тестовых примерах. Цель состоит в том, чтобы тестовый пример мог возвращать имитированные значения - EXPECT_CALL(mMockA, show()) .WillOnce(Return(false)); - person Programmer; 02.12.2017
comment
@Prakash Я немного расширил свой пример, как провести тест. - person user0042; 02.12.2017
comment
Спасибо, но я знаю, что во время компиляции возникает отдельная проблема, которая, как я полагаю, связана с созданием шаблонов класса A. На самом деле класс A определен в A.hpp и его реализация в A.cpp и то же самое для B - B.hpp и B .cpp - теперь, если я ссылаюсь на B.cpp как на B‹A›, даже если у меня есть #include A,hpp в нем, я получаю неопределенную ссылку на конструктор и методы A во время компиляции - хотя я не уверен, но мой анализ приводит к что в настоящее время - это то, что нам нужны шаблонные определения и объявления в одном файле - person Programmer; 02.12.2017
comment
@Prakash Конечно, для создания B шаблона требуется переместить все реализация появится в заголовке. Я серьезно рекомендую рассмотреть рефакторинг класса B, чтобы использовать ссылку на A, предоставленную при построении, вместо проектирования наследования. - person user0042; 02.12.2017
comment
@Prakash Я снова обновил свой ответ. Все больше и больше пахнет тем, что вы обнаружили недостаток дизайна, когда пытаетесь выполнить модульное тестирование своего кода. - person user0042; 02.12.2017
comment
Я нашел альтернативу решению, как указано ниже - обновите вопрос - person Programmer; 02.12.2017

Ну, приведенная ниже реализация помогла мне:

class A
{
public:
    virtual void Show(){}
};

class B : public A
public:
    void BMethod1(){Show()}
};

class BMock : public B
{
public:
   MOCK_METHOD0(Show, void());
};

Теперь используйте объект BMock для своих тестовых случаев.

person Programmer    schedule 02.12.2017

Вы можете использовать Isolator++ для создания теста без настройки:

class A
{
public:
    void Show() {}
};

class B : public A
{
public:
    void BMethod1() { Show(); }
};

TEST(BTEST, ShowMethod)
{
    B bobj;
    auto aobj = FAKE<A>();

    bobj.BMethod1();

    ASSERT_WAS_CALLED(aobj->Show());
}
person Sam    schedule 04.12.2017