Насмешливая стати c метод в с ++ - PullRequest
1 голос
/ 15 апреля 2020

Я только начал работать над модульным тестированием с помощью googleTest. У меня есть ситуация, когда у меня есть метод stati c, который вызывает один класс внутри другого класса

class A {
  public:
   static bool retriveJsonData(std::string name, Json::Value& responseJsonData);
}

В другом классе я использую метод класса A. retriveJsonData.

class B {
   public:
     bool Method1 (std::string name) {
        Json::Value sampleJsonData;
        return A::retriveJsonData(name, sampleJsonData);
 }

Насмешка над классом A

class MockA : public A {
  public:
    MOCK_MEHTOD2(retriveJsonData, bool(std::string, Json::Value));

}

Теперь я должен смоделировать retriveJsonData при тестировании метода 2 класса B с помощью EXPECT_CALL.

Пожалуйста, помогите мне решить, как можно проверить эту ситуацию?

Ответы [ 2 ]

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

Используйте A в качестве параметра шаблона в классе B (см. Современный дизайн C ++ ).

template <class T>
class B {
 public:
  bool Method1 (std::string name) {
     Json::Value sampleJsonData;
     return T::retriveJsonData(name, sampleJsonData);
  }
}

, затем в своих тестах используйте:

B<MockA> b;

In производственный код:

B<A> b;
0 голосов
/ 16 апреля 2020

Типы макетов в Google Mock предоставляют способы проверки ожидаемых вызовов для нестатических c функций-членов, где либо полиморфизм виртуальных функций, либо шаблоны могут использоваться в качестве «шва» для замены функций макета на реальные функции. Что здорово, если вы можете спроектировать или изменить все, чтобы использовать один из этих методов. Но иногда было бы обременительно заставить все работать таким образом в грязном унаследованном коде или в коде с использованием внешней библиотеки, и т. Д. c.

В этом случае другой вариант - определить функцию зависимости, которая не функция-не * stati c (то есть либо свободная функция, либо член stati c) для перенаправления на какой-то одноэлементный фиктивный объект. Предположим, у нас есть какой-то модуль перевода (B. cpp) для модульного тестирования, и он вызывает некоторую функцию, не являющуюся членом или stati c (A::retrieveJsonData), не определенную в этом модуле перевода.

Обычно для модульного тестирования B. cpp мы бы отметили необходимые символы компоновщика и предоставили поддельные определения для их заглушки, просто чтобы получить объектный файл Bo для ссылки в программу модульного тестирования:

// Fake definition:
bool A::retrieveJsonData(std::string, Json::Value&)
{ return false; }

В этом случае нам не нужно это поддельное определение; мы определим его позже для перенаправления на фиктивный объект.

Начнем с фиктивного класса специально для проблемных вызовов функций c. Если для проверки обычного способа существуют другие не * * * * * * * *, то этот класс НЕ совпадает с этими классами. (Если это необходимо для более чем одной функции, эти фиктивные классы могут быть выполнены для каждой функции, для каждого класса и / или для свободных функций, для библиотеки, один для всего; однако вы хотите настроить его.)

class Mock_A_Static {
public:
    Mock_A_Static() {
        EXPECT_EQ(instance, nullptr);
        instance = this;
    }
    ~Mock_A_Static() {
        EXPECT_EQ(instance, this);
        instance = nullptr;
    }

    MOCK_METHOD2(retrieveJsonData, bool(std::string, Json::Value&));

private:
    static Mock_A_Static* instance;
    friend class A;
};
Mock_A_Static* Mock_A_Static::instance = nullptr;

// The function code in B.cpp will actually be directly calling:
bool A::retrieveJsonData(std::string name, Json::Value& responseJsonData)
{
    EXPECT_NE(Mock_A_Static::instance, nullptr)
        << "Mock_A_Static function called but not set up";
    if (!Mock_A_Static::instance) return false;
    return Mock_A_Static::instance->retrieveJsonData(name, responseJsonData);
}

Затем просто поместите объект этого типа локально в тест или в класс фикстуры. (Только по одному за раз!)

TEST(BTest, Method1GetsJson)
{
    Mock_A_Static a_static;
    B b;
    EXPECT_CALL(a_static, retrieveJsonData(StrEq("data_x"), _));
    b.Method1("data_x");
}
...