Как GMOCK функцию внутри функции?

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

Display.cpp

    #include "Display.h"
int DisIp::getip()
{

return 5;

}
int  DisIp::display()
{
        Addition obj;
        int ip=obj.getip();
    return ip;
}

Дисплей.ч

class DisIP
{
public:
    int display();
        int getip();
};

GMOCK-файл

#include <limits.h>
#include "gmock.h"
#include "gtest.h"
#include "Display.h"
#include <string>
using namespace std;
using ::testing::AtLeast;
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Gt;
using ::testing::Return;
using testing::ReturnPointee;
using ::testing::Invoke;
class MyInterface{
public:

    virtual int display() = 0;
    virtual int getip()=0;
};

class MockInter : public MyInterface
{
public:
MockInter()
{
        ON_CALL(*this, getip()).WillByDefault(Invoke(&this, &MockInter::getip));
        ON_CALL(*this, display()).WillByDefault(Invoke(&real, &Addition::display));
}
MOCK_METHOD0(display,int());
MOCK_METHOD0(getip,int());
DisIp real;
};


class DisplayTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
  }

  virtual void TearDown() {
    // Code here will be called immediately after each test
    // (right before the destructor).
  }
};

TEST_F(DisplayTest,ip){
        MockInter mock;
//EXPECT_EQ(1,mock.display());
EXPECT_EQ(1,mock.getip());
}

person Prasanth Manoharan    schedule 28.02.2017    source источник
comment
Я боюсь, что это `ON_CALL(*this, getip()).WillByDefault(Invoke(&this, &MockInter::getip));` является бесконечной рекурсией...   -  person PiotrNycz    schedule 06.03.2017


Ответы (2)


Ваш дизайн страдает от нарушения принципа единой ответственности.

Отображение и получение IP — две разные обязанности. Это даже показано в вашей реализации DisIp::display() - вы получаете IP от так называемого Addition obj. Когда вы исправите эту ошибку проектирования, ваши модульные тесты станут намного проще и понятнее. Но важно сказать, что УТ здесь лишь симптом, плохой дизайн — это болезнь.

Итак, как это может выглядеть:

class IIpProvider
{
public:
  virtual ~IIpProvider() = default;
  virtual int getIp() = 0;
};

class DispIp
{
public:
    DispIp(IIpProvider& ipProvider) : ipProvider(ipProvider) {}
    int display()
    {
       int ip=ipProvider.getIp();
       //...
       return ip;
    }
private:
   IIpProvider& ipProvider;
};

тогда ваш макет:

class IpProviderMock : public IIpProvider
{
public:
  MOCK_METHOD0(getIp, int());
};

И ваши тесты:

class DispIpTest : public ::testing::Test
{
protected:
   IpProviderMock ipProviderMock;
   DispIp objectUnderTest{ipProviderMock}; // object-under-test must be connected to object doubles (like mocks)
};
TEST_F(DispIpTest, shallUseProvidedIpToDisplay)
{
    using namespace testing;
    auto SOME_IP = 7;
    EXPECT_CALL(ipProviderMock, getIp()).WillRepeatedly(Return(SOME_IP));
    //...
    ASSERT_EQ(SOME_IP, objectUnderTest.display());
}

В ваших первоначальных тестах основная проблема заключалась также в том, что ваш фиктивный объект никак не был связан с тестируемым объектом.


Если вам не нравится (не может) изменять свой дизайн (что я действительно советую), вы должны использовать метод под названием частичный макет

В вашем случае - это будет примерно так:

class DisIP
{
public:
    int display();
    virtual int getip(); // function for partial mocking must be virtual
};
class DisIPGetIpMock : public DisIP
{
public:
      MOCK_METHOD0(getIp, int());
};
class DispIpTest : public ::testing::Test
{
protected:
   DisIPGetIpMock objectUnderTest; 
};

TEST_F(DispIpTest, shallUseProvidedIpToDisplay)
{
    EXPECT_CALL(objectUnderTest, getIp()).WillRepeatedly(Return(SOME_IP));
    ...
    ASSERT_EQ(SOME_IP, objectUnderTest.display());
}
person PiotrNycz    schedule 06.03.2017
comment
Первый фрагмент (не частичный издевательский) не компилируется. Я получаю сообщение об ошибке: gtest5.cpp: в конструкторе 'DisIP::DisIP(IIpProvider&)': gtest5.cpp:26:63: ошибка: неверная инициализация ссылки типа 'IpProviderMock&' из выражения типа 'IIpProvider' gtest5.cpp : В глобальном масштабе: gtest5.cpp:40:31: ошибка: 'ipProviderMock' не является типом gtest5.cpp: В функции-члене 'virtual void DispIpTest_shallUseProvidedIpToDisplay_Test::TestBody()': gtest5.cpp:46:5: ошибка: '((DispIpTest_shallUseProvidedIpToDisplay_Test*)this)-›DispIpTest::objectUnderTest' не имеет типа класса - person Dipankar Saha; 05.06.2017
comment
@DipankarSaha Не уверен, что проблема в этом, но имя деструктора IIpProvider было неправильным. Теперь это исправлено. - person PiotrNycz; 05.06.2017
comment
Что я исправил это в своем тестовом коде, так что это не проблема. Не уверен, почему следующая строка вызывает проблемы. DispIp objectUnderTest{ipProviderMock}; Хотя я предполагаю, что вместо {} было бы () -> gtest5.cpp:40:31: ошибка: ‘ipProviderMock’ не является типом - person Dipankar Saha; 05.06.2017
comment
@DipankarSaha исправил - теперь компилируется. Это были просто опечатки - типа DisIP -> DispIp... - person PiotrNycz; 05.06.2017
comment
Поскольку в одном комментарии невозможно учесть ошибку, которую я получаю от компилятора, поэтому пишу в отдельном комментарии. $ g++ -isystem /home/dipankar/Downloads/googletest-master/googletest/include/ -isystem /home/dipankar/Downloads/googletest-master/googlemock/include/ -pthread gtest9.cpp /home/dipankar/Downloads/googletest- master/googlemock/make/libgmock.a gtest9.cpp:14:28: предупреждение: функции по умолчанию и удаленные доступны только с -std=c++0x или -std=gnu++0x [включено по умолчанию] gtest9.cpp: 14:28: ошибка: 'виртуальный IIpProvider::~IIpProvider()', объявленный виртуальным, не может быть установлен по умолчанию в теле класса - person Dipankar Saha; 06.06.2017
comment
gtest9.cpp:32:7: ошибка: более свободный спецификатор броска для 'виртуального IpProviderMock::~IpProviderMock()' gtest9.cpp:14:11: ошибка: переопределение 'виртуального IIpProvider::~IIpProvider() throw()' gtest9. cpp:42:11: ошибка: определение функции не объявляет параметры gtest9.cpp: в функции-члене 'virtual void DispIpTest_shallUseProvidedIpToDisplay_Test::TestBody()': gtest9.cpp:47:10: ошибка: "SOME_IP" не указывает тип gtest9.cpp:48:64: ошибка: «SOME_IP» не был объявлен в этой области gtest9.cpp:50:5: ошибка: аргумент шаблона 1 недействителен - person Dipankar Saha; 06.06.2017
comment
gtest9.cpp: 50: 5: ошибка: «objectUnderTest» не был объявлен в этой области - person Dipankar Saha; 06.06.2017
comment
Можете ли вы показать мне, как вы компилируете. Способ компиляции приведен выше (вместе с журналом ошибок). - person Dipankar Saha; 06.06.2017
comment
@DipankarSaha Я компилирую с -std=c++14 (gcc5,3). Я вижу, что ваш компилятор довольно старый. Если у вас есть такие ошибки, как «виртуальный IIpProvider::~IIpProvider()», объявленный виртуальным, не может быть установлен по умолчанию в теле класса, замените его реализацию стилем до C++11, например virtual ~IIpProvider() {} - person PiotrNycz; 06.06.2017
comment
Ok. Теперь я получаю: gtest9.cpp:42:11: error: function definition does not declare parameters gtest9.cpp: In member function ‘virtual void DispIpTest_shallUseProvidedIpToDisplay_Test::TestBody()’: gtest9.cpp:49:5: error: ‘objectUnderTest’ was not declared in this scope. Так что в основном я получаю ошибку в этой строке DispIp objectUnderTest{ipProviderMock}; - person Dipankar Saha; 06.06.2017
comment
Также упомянуть об этом, если я сделаю DispIp objectUnderTest(ipProviderMock);. Затем получаю следующую ошибку: gtest9.cpp:42:27: error: ‘ipProviderMock’ is not a type gtest9.cpp: In member function ‘virtual void DispIpTest_shallUseProvidedIpToDisplay_Test::TestBody()’: gtest9.cpp:48:5: error: ‘((DispIpTest_shallUseProvidedIpToDisplay_Test*)this)->DispIpTest::objectUnderTest’ does not have class type - person Dipankar Saha; 06.06.2017
comment
@DipankarSaha Поскольку в вашем компиляторе нет инициализации в классе - см. and-non-const-members-what-c" title="c11 позволяет инициализировать в классе нестатические и неконстантные члены, что c">stackoverflow.com/questions/13662441/ Вы не можете ожидать, что люди будут использовать древний C++, чтобы сделать ваш старый компилятор счастливым. Вы должны погуглить или спросить SO о предупреждениях вашего компилятора - или просто использовать -std=c++11 по крайней мере в своей командной строке. Я имею в виду - в текущем режиме, когда я просматриваю ваши задачи раз в день - это займет недели, пока вы не скомпилируете... - person PiotrNycz; 06.06.2017
comment
Привет PiotrNycz, большое спасибо. Действительно, из-за моего старого компилятора он не компилировался. Спасибо :) - person Dipankar Saha; 07.06.2017

Вы можете использовать библиотеку Cutie, чтобы имитировать функцию C в стиле GoogleMock, если это вам поможет.
В репозитории есть полный семпл, но это просто вкус:

INSTALL_MOCK(fclose);
CUTIE_EXPECT_CALL(fclose, _).WillOnce(Return(i));
person MrDor    schedule 06.07.2020