2016-01-13 2 views
2

Обычно в тестовых системах, когда мы пишем новый тестовый тест, нам нужно где-то зарегистрировать тестовый файл, чтобы его можно было вызвать.Как автоматически регистрировать тестовые примеры в тестовой системе?

Например, в тестовой системе: TESTCASE(a,b){...} можно сопоставить void testcase_a_b() {...} и тестовая система может назвать каждый из этих void testcase_a_b(), void testcase_c_d() и т.д. от основной и, следовательно, выполнять все тестовые случаи.

Каков способ автоматической регистрации тестовых примеров в исполняемом файле? Например, в Google Test (как и в нескольких других тестовых средах), если мы вызываем RUN_ALL_TESTS(), он автоматически выполняет все декларации, начинающиеся с TEST(a,b) и т. Д. В исполняемом файле.

Как Google Test знает о существовании TEST(a,b) в exe? Я пытаюсь понять (с точки зрения высокого уровня дизайна), что было бы простым способом реализовать такую ​​систему, как на C++. где макрос, такой как TEST (a, b), автоматически присоединяется к списку допустимых тестовых примеров, поэтому его можно запустить из main, не беспокоясь о его регистрации отдельно.

ответ

2

Как правило, это делается путем создания глобальных объектов, которые вызывают метод регистрации при их создании. Это противоречит общепризнанным «хорошим практикам» на C++ (см. https://isocpp.org/wiki/faq/ctors#static-init-order), поэтому перед попыткой такой реализации вы должны разбираться в этих проблемах.

В любом случае, это метод googletest использования - TEST макрос препроцессора в конечном счете сводится к этому (GTEST-internal.h):

// Helper macro for defining tests. 
#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ 
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ 
public:\ 
    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ 
private:\ 
    virtual void TestBody();\ 
    static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ 
    GTEST_DISALLOW_COPY_AND_ASSIGN_(\ 
     GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ 
};\ 
\ 
::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ 
    ::test_info_ =\ 
    ::testing::internal::MakeAndRegisterTestInfo(\ 
     #test_case_name, #test_name, NULL, NULL, \ 
     (parent_id), \ 
     parent_class::SetUpTestCase, \ 
     parent_class::TearDownTestCase, \ 
     new ::testing::internal::TestFactoryImpl<\ 
      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ 
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() 

Итак, когда вы используете этот макрос, глобальный экземпляр класс, который вызывает ::testing::internal::MakeAndRegisterTestInfo с параметрами, соответствующими тестовому сценарию.

+0

Спасибо за ответ. Итак, что по вашему мнению является хорошим способом разработки системы, которая достигает тех же результатов без использования статической инициализации? Или нет другого пути? –

+0

Если вы хотите, чтобы что-то произошло до вызова 'main', вам придется полагаться на статическую инициализацию. Очевидно, что Google решил реализовать его таким образом - я просто предупреждаю, что нужно тщательно соблюдать это, потому что было бы очень легко создать нестабильную реализацию, как описано в FAQ на C++. – MuertoExcobito

+0

Ваша помощь очень ценится :) Большое спасибо. –

Смежные вопросы