Usually in test systems when we write a new testcase we need to register the test case somewhere so that it can be called.
For example in a test system :
TESTCASE(a,b){...}
can map to void testcase_a_b() {...}
and the test system may call each of these void testcase_a_b()
, void testcase_c_d()
etc. from main and hence run all the test cases.
What is the way to auto-register test cases in an executable? For example, in Google Test (just like several other test frameworks), if we call RUN_ALL_TESTS()
it automatically executes all the declarations starting with TEST(a,b)
etc. in the executable.
How does Google Test know about the existence of TEST(a,b)
in the exe ? I am trying to understand(from a high level design perspective) what would be a simple way to implement a system like that one in C++. where a macro like TEST(a,b) automatically appends itself to the list of valid test cases, so that it can be run from main without worrying about registering it separately.
Generally this is done by creating global objects, which call a registration method when they are constructed. This goes against generally regarded "good practices" in C++ (see https://isocpp.org/wiki/faq/ctors#static-init-order), so you should be quite versed in these issues before attempting such an implementation.
Regardless, this is the method googletest uses - the TEST
preprocessor macro eventually boils down to this (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()
So, when you use this macro, a global instance of a class which calls ::testing::internal::MakeAndRegisterTestInfo
with parameters corresponding to the test case.