Я провожу модульное тестирование с использованием фреймворков gtest и gmock, и мне нужна помощь в создании заглушек / насмешек над внешними C функциями, используемыми внутри функций класса - PullRequest
2 голосов
/ 28 апреля 2020

Итак, я пытаюсь написать тестовые примеры для моего производственного кода, но охват крайне низок из-за использования некоторой внешней библиотеки C, которая не может быть выполнена без целевого оборудования, поэтому у меня нет выбора, кроме как заглушить то же самое , Теперь проблема в том, как заглушить функцию C?

Мой рабочий код: prod_code. cpp

 int TargetTestClass::targetFunc()
 {
    if(externalCFunc() == True)
    {
        statement1; statement2; statement3; /// and so on
    }
 }

Мой тест-код. cpp обычно содержит такие тесты, как этот

//Fixture for Target Test class
class TargetTestClassFixture : public testing::Test {
      TargetTestClass* targetTestClassPtr;
      void SetUp() {
         targetTestClassPtr = new TargetTestClass();
      }
      void TearDown() {
         delete targetTestClassPtr;
      }
  };



TEST_F (unitTest, test_001)
  {
       targetTestClassPtr->targetFunc(); //Need to do something here so that externalCFunc() returns true on call
  }

Ответы [ 2 ]

2 голосов
/ 28 апреля 2020

Что вы можете сделать, это создать исходный файл, такой как my_c_stubs. c, где вы можете реализовать свою C функцию. Например, реализация может просто вернуть true. Тогда не связывайте исходный файл с внешней функцией C, а используйте файл-заглушку. Вы все равно должны использовать оригинальный заголовок C. Таким образом, вы не сможете заглушить встроенные функции. Если это требуется, необходим более сложный подход.

1 голос
/ 28 апреля 2020

Я нашел 2 решения для моей проблемы, поэтому я собираюсь ответить на этот вопрос здесь.

Решение 1: Это включало изменение целевого исходного кода. По сути, вам нужно написать оболочку, которая вызывает внешние C функции, как показано ниже

Class TargetTestClass{
    protected:
        int targetFunc();
        virtual int externalCFuncWrapper();  // Wrapper
};

//call the external C function from the wrapper
int TargetTestClass::externalCFunctionWrapper(){
    return(externalCFunc());
}

//Definition of targetFuc in original question

//Now write a mock class for Target Test Class as usual and mock the wrapper function to return what you want to 

class MockTargetTestClass : public TargetTestClass{
    public: MOCK_METHOD0(externalCFunctionWrapper, int());
};

//Now use the Mock class as needed
TEST_F ( TargetUnitTest, TestingExternalCFuctionCall)
{
    MockTargetTestClass mockTargetTestClassObj;
    using ::testing::Return;
    using ::testing::_;
    Expect_Call(mockTargetTestClassObj, externalCFunctionWrapper())
    .WillOnce(Return(1));

    Assert_EQ(mockTargetTestClassObj.targetFunc(), 1);
}

Решение 2. Благодаря @kreynolds я посмотрел на Fake Function Framework и реализовал следующим образом:

Class TargetTestClass{
    protected:
        int targetFunc();
        //No Code change needed in target source code
};

//In testcode.cpp 

#include <gmock-global/gmock-global.h>

MOCK_GLOBAL_FUNC0(externalCFunc, int());

TEST( Unittest, test002){
    using ::testing::Return;
    using ::testing::_;
    EXPECT_GLOBAL_CALL(externalCFunc, externalCFunc()).WillOnce(Return(1));

    TargetTestClass targetFunc; //This does not contain any wrapper
    EXPECT_EQ(targetTestClassObj.targetFunc(), 1);
}

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

Еще раз спасибо всем за то, что вы уделили нам время.

...