Единичное тестирование частных методов

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

До сих пор я придумал использование.

#define private public

Но я не доволен этим, так как он уничтожит все инкапсуляции с точки зрения unit test.

Какие методы вы используете для модульных тестов частных методов.

Ответ 1

Если методы достаточно сложны, чтобы гарантировать тестирование изолированно, то реорганизуйте их в свои собственные классы и протестируйте через их публичный интерфейс (интерфейсы). Затем используйте их конфиденциально в исходном классе.

Ответ 2

Вместо неприятного взлома #define, о котором вы упоминаете в вопросе, более чистым механизмом является проверка теста подкласса класса. Это позволяет тестовому коду (и только тестовому коду) обращаться к рядовым, защищая их от всего остального.

Тем не менее, желательно протестировать через открытый интерфейс. Если ваш класс X имеет много кода в частных функциях-членах, возможно, стоит извлечь новый класс Y, который используется реализацией класса X. Этот новый класс Y затем может быть протестирован через его открытый интерфейс, не подвергая его использовать для клиентов класса X.

Ответ 3

Если вы используете Google Test, вы можете использовать FRIEND_TEST, чтобы легко объявить свое тестовое оборудование как друга тестируемого класса.

И знаете, если тестирование частных функций было недвусмысленно плохим, как говорили некоторые другие ответы, то, вероятно, он не будет встроен в Google Test.

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

Ответ 4

Сделайте тестовый класс как друга исходного класса. Это объявление друга будет находиться внутри флага #define UNIT_TEST.

class To_test_class {
   #ifdef UNIT_TEST
     friend test_class;
   #endif
}

Теперь для вашего unit test вы скомпилируете код с флагом -DUNIT_TEST. Таким образом, вы сможете проверить частную функцию.

Теперь ваш код unit test не будет помещен в производственную среду, так как флаг UNIT_TEST будет false. Следовательно, код по-прежнему безопасен.

Также вам не понадобится специальная библиотека для модульного тестирования.

Ответ 5

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

Измените метод, который вы хотите протестировать, от private до protected. Для других классов метод по-прежнему будет private, но теперь вы можете получить класс "тестирования" из вашего базового класса, который предоставляет частную функциональность, которую вы хотите протестировать.

Здесь минимальный пример:

class BASE_CLASS {
  protected:
    int your_method(int a, int b);
};

class TEST_CLASS : public BASE_CLASS {
  public:
    int your_method(int a, int b) {
      return BASE_CLASS::your_method(a, b);
    }
}

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

Ответ 6

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

Теперь, как уже упоминалось несколько человек, обсуждается, следует ли вообще тестировать частные методы. Но это не распространяется на случай, когда вы намеренно скрывали конструкторы для ограничения экземпляров определенных областей или нескольких других более эзотерических случаев.

Кроме того, вы не можете связать пространство имен, а "дружба" не наследуется на С++, поэтому в зависимости от структуры вашего модуля тестирования у вас могут быть проблемы. К счастью, если вы используете Boost.Test, там в элегантном решении этой проблемы в виде Fixtures.

http://www.boost.org/doc/libs/1_52_0/libs/test/doc/html/utf/user-guide/fixture/per-test-case.html

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

Макрос BOOST_FIXTURE_TEST_CASE позаботится о том, чтобы создать экземпляр и снести ваше приспособление для вас.

Ответ 7

После многих часов это то, что я решил стать лучшим решением для тех, кто хочет проверить свои частные функции. Это комбинация ответов Max DeLiso и Miloš.

Если вы используете boost:: unit-test, тогда есть простое и элегантное решение.

  • Используйте protected вместо private в своих классах

    /* MyClass.hpp */
    
    class MyClass {
    
    protected:
        int test() {
            return 1;
        }
    };
    
  • Создайте приспособление:

    /* TestMyClass.cpp */
    
    class F : public MyClass {};
    
    
    BOOST_FIXTURE_TEST_SUITE(SomeTests, F)
    
    // use any protected methods inside your tests
    BOOST_AUTO_TEST_CASE(init_test)
    {
        BOOST_CHECK_EQUAL( test(), 1 );
    }
    BOOST_AUTO_TEST_SUITE_END()
    

Таким образом, вы можете свободно использовать любую из функций MyClass без #define private public или добавлять к вам друзей!

Ответ 8

Я не думаю, что для частных методов потребуется unit test.

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