diff --git a/CMake/mitkMacroCreateModuleTests.cmake b/CMake/mitkMacroCreateModuleTests.cmake index c6d0996a2f..c90d323e4d 100644 --- a/CMake/mitkMacroCreateModuleTests.cmake +++ b/CMake/mitkMacroCreateModuleTests.cmake @@ -1,114 +1,128 @@ # # Create tests and testdriver for this module # # Usage: MITK_CREATE_MODULE_TESTS( [EXTRA_DRIVER_INIT init_code] ) # # EXTRA_DRIVER_INIT is inserted as c++ code in the testdriver and will be executed before each test # macro(MITK_CREATE_MODULE_TESTS) MACRO_PARSE_ARGUMENTS(MODULE_TEST "EXTRA_DRIVER_INIT;EXTRA_DRIVER_INCLUDE;EXTRA_DEPENDS" "" ${ARGN}) if(BUILD_TESTING AND MODULE_IS_ENABLED) set(OLD_MOC_H_FILES ${MOC_H_FILES}) set(MOC_H_FILES) include(files.cmake) include_directories(.) if(DEFINED MOC_H_FILES) QT4_WRAP_CPP(MODULE_TEST_GENERATED_MOC_CPP ${MOC_H_FILES} OPTIONS -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) endif(DEFINED MOC_H_FILES) - if (MODULE_TEST_EXTRA_DEPENDS) - MITK_USE_MODULE("${MODULE_TEST_EXTRA_DEPENDS}") - include_directories(${ALL_INCLUDE_DIRECTORIES}) - endif() + MITK_USE_MODULE(CppUnit ${MODULE_TEST_EXTRA_DEPENDS}) + include_directories(${ALL_INCLUDE_DIRECTORIES}) + + set(TESTDRIVER ${MODULE_NAME}TestDriver) - set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN "mitk::LoggingBackend::Register(); ${MODULE_TEST_EXTRA_DRIVER_INIT};") + # Write a header file containing include directives and custom code + # for the test driver. + set(_extra_include_content ) + list(APPEND MODULE_TEST_EXTRA_DRIVER_INCLUDE "mitkLog.h") + list(REMOVE_DUPLICATES MODULE_TEST_EXTRA_DRIVER_INCLUDE) + foreach(_include ${MODULE_TEST_EXTRA_DRIVER_INCLUDE}) + set(_extra_include_content "${extra_include_content} +#include <${_include}>") + endforeach() + set(_extra_include_content "${_extra_include_content} +#include +std::vector globalCmdLineArgs;") + set(_extra_include_file ${CMAKE_CURRENT_BINARY_DIR}/${TESTDRIVER}_extras.h) + file(WRITE ${_extra_include_file} "${_extra_include_content}") + + set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " +for (std::size_t avIndex = 1; avIndex < ac; ++avIndex) globalCmdLineArgs.push_back(av[avIndex]); +mitk::LoggingBackend::Register(); +${MODULE_TEST_EXTRA_DRIVER_INIT}" +) set(CMAKE_TESTDRIVER_AFTER_TESTMAIN "mitk::LoggingBackend::Unregister();") - if(NOT MODULE_TEST_EXTRA_DRIVER_INCLUDE) - # this is necessary to make the LoggingBackend calls available if nothing else is included - set(MODULE_TEST_EXTRA_DRIVER_INCLUDE "mitkLog.h") - endif(NOT MODULE_TEST_EXTRA_DRIVER_INCLUDE) create_test_sourcelist(MODULETEST_SOURCE ${MODULE_NAME}TestDriver.cpp ${MODULE_TESTS} ${MODULE_IMAGE_TESTS} ${MODULE_SURFACE_TESTS} ${MODULE_CUSTOM_TESTS} - EXTRA_INCLUDE ${MODULE_TEST_EXTRA_DRIVER_INCLUDE} + EXTRA_INCLUDE ${_extra_include_file} ) - set(TESTDRIVER ${MODULE_NAME}TestDriver) add_executable(${TESTDRIVER} ${MODULETEST_SOURCE} ${MODULE_TEST_GENERATED_MOC_CPP} ${TEST_CPP_FILES}) target_link_libraries(${TESTDRIVER} ${MODULE_PROVIDES} ${ALL_LIBRARIES}) if(MODULE_SUBPROJECTS) foreach(subproject ${MODULE_SUBPROJECTS}) add_dependencies(${subproject} ${TESTDRIVER}) endforeach() endif() # # Now tell CMake which tests should be run. This is done automatically # for all tests in ${KITNAME}_TESTS and ${KITNAME}_IMAGE_TESTS. The IMAGE_TESTS # are run for each image in the TESTIMAGES list. # foreach( test ${MODULE_TESTS} ) get_filename_component(TName ${test} NAME_WE) add_test(${TName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName}) # Add labels for CDash subproject support if(MODULE_SUBPROJECTS) set_property(TEST ${TName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() endforeach( test ) foreach(image ${MODULE_TESTIMAGES} ${ADDITIONAL_TEST_IMAGES} ) if(EXISTS ${image}) set(IMAGE_FULL_PATH ${image}) else(EXISTS ${image}) # todo: maybe search other paths as well # yes, please in mitk/Testing/Data, too set(IMAGE_FULL_PATH ${MITK_DATA_DIR}/${image}) endif(EXISTS ${image}) if(EXISTS ${IMAGE_FULL_PATH}) foreach( test ${MODULE_IMAGE_TESTS} ) get_filename_component(TName ${test} NAME_WE) get_filename_component(ImageName ${IMAGE_FULL_PATH} NAME) add_test(${TName}_${ImageName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName} ${IMAGE_FULL_PATH}) # Add labels for CDash subproject support if(MODULE_SUBPROJECTS) set_property(TEST ${TName}_${ImageName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() endforeach( test ) else(EXISTS ${IMAGE_FULL_PATH}) message("!!!!! No such file: ${IMAGE_FULL_PATH} !!!!!") endif(EXISTS ${IMAGE_FULL_PATH}) endforeach( image ) foreach(surface ${MODULE_TESTSURFACES} ${ADDITIONAL_TEST_SURFACES} ) if(EXISTS ${surface}) set(SURFACE_FULL_PATH ${surface}) else(EXISTS ${surface}) # todo: maybe search other paths as well # yes, please in mitk/Testing/Data, too set(SURFACE_FULL_PATH ${MITK_DATA_DIR}/${surface}) endif(EXISTS ${surface}) if(EXISTS ${SURFACE_FULL_PATH}) foreach( test ${MODULE_SURFACE_TESTS} ) get_filename_component(TName ${test} NAME_WE) get_filename_component(SurfaceName ${SURFACE_FULL_PATH} NAME) add_test(${TName}_${SurfaceName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName} ${SURFACE_FULL_PATH}) # Add labels for CDash subproject support if(MODULE_SUBPROJECTS) set_property(TEST ${TName}_${SurfaceName} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() endforeach( test ) else(EXISTS ${SURFACE_FULL_PATH}) message("!!!!! No such surface file: ${SURFACE_FULL_PATH} !!!!!") endif(EXISTS ${SURFACE_FULL_PATH}) endforeach( surface ) set(MOC_H_FILES ${OLD_MOC_H_FILES}) endif(BUILD_TESTING AND MODULE_IS_ENABLED) endmacro(MITK_CREATE_MODULE_TESTS) diff --git a/Core/Code/Common/mitkParameterizedTestCaller.h b/Core/Code/Common/mitkParameterizedTestCaller.h new file mode 100644 index 0000000000..e9500a95b1 --- /dev/null +++ b/Core/Code/Common/mitkParameterizedTestCaller.h @@ -0,0 +1,124 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKPARAMETERIZEDTESTCALLER_H +#define MITKPARAMETERIZEDTESTCALLER_H + +#include "cppunit/TestCase.h" + +#include +#include + +extern std::vector globalCmdLineArgs; + +namespace mitk { + +template +class ParameterizedTestCaller : public CppUnit::TestCase +{ + typedef void (ParameterizedFixture::*TestMethod)(); + +public: + + /** + * Constructor for TestCaller. This constructor builds a new ParameterizedFixture + * instance owned by the ParameterizedTestCaller. + * \param name name of this ParameterizedTestCaller + * \param test the method this ParameterizedTestCaller calls in runTest() + */ + ParameterizedTestCaller(const std::string& name, TestMethod test) + : TestCase(name) + , m_OwnFixture(true) + , m_Fixture(new ParameterizedFixture()) + , m_Test(test) + { + } + + /** + * Constructor for ParameterizedTestCaller. + * This constructor does not create a new ParameterizedFixture instance but accepts + * an existing one as parameter. The ParameterizedTestCaller will not own the + * ParameterizedFixture object. + * \param name name of this TestCaller + * \param test the method this TestCaller calls in runTest() + * \param fixture the Fixture to invoke the test method on. + */ + ParameterizedTestCaller(const std::string& name, TestMethod test, ParameterizedFixture& fixture) + : TestCase(name) + , m_OwnFixture(false) + , m_Fixture(&fixture) + , m_Test(test) + { + } + + /** + * Constructor for ParameterizedTestCaller. + * This constructor does not create a new ParameterizedFixture instance but accepts + * an existing one as parameter. The ParameterizedTestCaller will own the + * ParameterizedFixture object and delete it in its destructor. + * \param name name of this TestCaller + * \param test the method this TestCaller calls in runTest() + * \param fixture the Fixture to invoke the test method on. + */ + ParameterizedTestCaller(const std::string& name, TestMethod test, ParameterizedFixture* fixture) + : TestCase(name) + , m_OwnFixture(true) + , m_Fixture(fixture) + , m_Test(test) + { + } + + ~ParameterizedTestCaller() + { + if (m_OwnFixture) + delete m_Fixture; + } + + void runTest() + { + (m_Fixture->*m_Test)(); + } + + void setUp() + { + m_Fixture->setUpParameter(globalCmdLineArgs); + m_Fixture->setUp(); + } + + void tearDown() + { + m_Fixture->tearDown(); + } + + std::string toString() const + { + return "TestCaller " + getName(); + } + +private: + ParameterizedTestCaller(const ParameterizedTestCaller& other); + ParameterizedTestCaller& operator =(const ParameterizedTestCaller& other); + +private: + bool m_OwnFixture; + ParameterizedFixture* m_Fixture; + TestMethod m_Test; + std::vector m_Parameter; +}; + +} + +#endif // MITKPARAMETERIZEDTESTCALLER_H diff --git a/Core/Code/Common/mitkParameterizedTestFixture.h b/Core/Code/Common/mitkParameterizedTestFixture.h new file mode 100644 index 0000000000..f8b05bea8c --- /dev/null +++ b/Core/Code/Common/mitkParameterizedTestFixture.h @@ -0,0 +1,38 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKPARAMETERIZEDTESTFIXTURE_H +#define MITKPARAMETERIZEDTESTFIXTURE_H + +#include + +#include +#include + +namespace mitk { + +class ParameterizedTestFixture : public CppUnit::TestFixture +{ + +public: + + virtual void setUpParameter(const std::vector& parameter) {} + +}; + +} + +#endif // MITKPARAMETERIZEDTESTFIXTURE_H diff --git a/Core/Code/Common/mitkTestingMacros.h b/Core/Code/Common/mitkTestingMacros.h index da2ae0420e..e1d9e88681 100644 --- a/Core/Code/Common/mitkTestingMacros.h +++ b/Core/Code/Common/mitkTestingMacros.h @@ -1,187 +1,281 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include +#include + +#include +#include "cppunit/ui/text/TestRunner.h" namespace mitk { - /** \brief Indicate a failed test. */ + /** @brief Indicate a failed test. */ class TestFailedException : public std::exception { public: TestFailedException() {} }; } /** - * - * \brief Output some text without generating a terminating newline. Include + * @brief Output some text without generating a terminating newline. Include * * @ingroup MITKTestingAPI - * - * */ + */ #define MITK_TEST_OUTPUT_NO_ENDL(x) \ std::cout x ; -/** \brief Output some text. - - @ingroup MITKTestingAPI -*/ +/** + * @brief Output some text. + * + * @ingroup MITKTestingAPI + */ #define MITK_TEST_OUTPUT(x) \ MITK_TEST_OUTPUT_NO_ENDL(x << "\n") -/** \brief Do some general test preparations. Must be called first in the - main test function. - - @ingroup MITKTestingAPI -*/ +/** + * @brief Do some general test preparations. Must be called first in the + * main test function. + * + * @deprecatedSince{2013_09} Use MITK_TEST_SUITE_REGISTRATION instead. + * @ingroup MITKTestingAPI + */ #define MITK_TEST_BEGIN(testName) \ std::string mitkTestName(#testName); \ mitk::TestManager::GetInstance()->Initialize(); \ try { -/** \brief Fail and finish test with message MSG - @ingroup MITKTestingAPI -*/ +/** + * @brief Fail and finish test with message MSG + * + * @deprecatedSince{2013_09} Use CPPUNIT_FAIL instead + * @ingroup MITKTestingAPI + */ #define MITK_TEST_FAILED_MSG(MSG) \ MITK_TEST_OUTPUT(MSG) \ throw mitk::TestFailedException(); -/** \brief Must be called last in the main test function. +/** + * @brief Must be called last in the main test function. + * + * @deprecatedSince{2013_09} Use MITK_TEST_SUITE_REGISTRATION isntead. * @ingroup MITKTestingAPI -*/ + */ #define MITK_TEST_END() \ } catch (mitk::TestFailedException ex) { \ MITK_TEST_OUTPUT(<< "Further test execution skipped.") \ mitk::TestManager::GetInstance()->TestFailed(); \ } catch (std::exception ex) { \ MITK_TEST_OUTPUT(<< "std::exception occured " << ex.what()) \ mitk::TestManager::GetInstance()->TestFailed(); \ } \ if (mitk::TestManager::GetInstance()->NumberOfFailedTests() > 0) { \ MITK_TEST_OUTPUT(<< mitkTestName << ": [DONE FAILED] , subtests passed: " << \ mitk::TestManager::GetInstance()->NumberOfPassedTests() << " failed: " << \ mitk::TestManager::GetInstance()->NumberOfFailedTests() ) \ return EXIT_FAILURE; \ } else { \ MITK_TEST_OUTPUT(<< mitkTestName << ": " \ << mitk::TestManager::GetInstance()->NumberOfPassedTests() \ << " tests [DONE PASSED]") \ return EXIT_SUCCESS; \ } \ +/** + * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT or CPPUNIT_ASSERT_MESSAGE instead. + */ #define MITK_TEST_CONDITION(COND,MSG) \ MITK_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ mitk::TestManager::GetInstance()->TestFailed(); \ MITK_TEST_OUTPUT(<< " [FAILED]\n" << "In " << __FILE__ \ << ", line " << __LINE__ \ << ": " #COND " : [FAILED]") \ } else { \ MITK_TEST_OUTPUT(<< " [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } +/** + * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT or CPPUNIT_ASSERT_MESSAGE instead. + */ #define MITK_TEST_CONDITION_REQUIRED(COND,MSG) \ MITK_TEST_OUTPUT_NO_ENDL(<< MSG) \ if ( ! (COND) ) { \ MITK_TEST_FAILED_MSG(<< " [FAILED]\n" << " +--> in " << __FILE__ \ << ", line " << __LINE__ \ << ", expression is false: \"" #COND "\"") \ } else { \ MITK_TEST_OUTPUT(<< " [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } /** * \brief Begin block which should be checked for exceptions * + * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT_THROW instead. * @ingroup MITKTestingAPI * * This macro, together with MITK_TEST_FOR_EXCEPTION_END, can be used * to test whether a code block throws an expected exception. The test FAILS if the * exception is NOT thrown. A simple example: * MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ImageFileReaderException) typedef itk::ImageFileReader< itk::Image > ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName("/tmp/not-existing"); reader->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ImageFileReaderException) * */ #define MITK_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ try { +/** + * @deprecatedSince{2013_09} + */ #define MITK_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) \ mitk::TestManager::GetInstance()->TestFailed(); \ MITK_TEST_OUTPUT( << "Expected an '" << #EXCEPTIONCLASS << "' exception. [FAILED]") \ } \ catch (EXCEPTIONCLASS) { \ MITK_TEST_OUTPUT( << "Caught an expected '" << #EXCEPTIONCLASS \ << "' exception. [PASSED]") \ mitk::TestManager::GetInstance()->TestPassed(); \ } /** - * \brief Simplified version of MITK_TEST_FOR_EXCEPTION_BEGIN / END for + * @brief Simplified version of MITK_TEST_FOR_EXCEPTION_BEGIN / END for * a single statement * + * @deprecatedSince{2013_09} Use CPPUNIT_ASSERT_THROW instead. * @ingroup MITKTestingAPI */ #define MITK_TEST_FOR_EXCEPTION(EXCEPTIONCLASS, STATEMENT) \ MITK_TEST_FOR_EXCEPTION_BEGIN(EXCEPTIONCLASS) \ STATEMENT ; \ MITK_TEST_FOR_EXCEPTION_END(EXCEPTIONCLASS) -/** \brief Testing macro to test if two objects are equal. +/** + * @brief Testing macro to test if two objects are equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. * Feel free to implement mitk::Equal for your own datatype or purpose. * + * @deprecatedSince{2013_09} Use MITK_ASSERT_EQUAL instead. + * * @param OBJ1 First object. * @param OBJ2 Second object. * @param MSG Message to appear with the test. */ #define MITK_TEST_EQUAL(OBJ1,OBJ2,MSG) \ MITK_TEST_CONDITION_REQUIRED( mitk::Equal(OBJ1, OBJ2, mitk::eps, true)==true, MSG) -/** \brief Testing macro to test if two objects are not equal. +/** + * @brief Testing macro to test if two objects are equal. * * @ingroup MITKTestingAPI * * This macro uses mitk::eps and the corresponding mitk::Equal methods for all * comparisons and will give verbose output on the dashboard/console. + * Feel free to implement mitk::Equal for your own datatype or purpose. + * + * @param EXPECTED First object. + * @param ACTUAL Second object. + * @param MSG Message to appear with the test. + */ +#define MITK_ASSERT_EQUAL(EXPECTED, ACTUAL, MSG) \ + CPPUNIT_ASSERT_MESSAGE(MSG, mitk::Equal(EXPECTED, ACTUAL, mitk::eps, true)) + +/** + * @brief Testing macro to test if two objects are not equal. + * + * @ingroup MITKTestingAPI + * + * This macro uses mitk::eps and the corresponding mitk::Equal methods for all + * comparisons and will give verbose output on the dashboard/console. + * + * @deprecatedSince{2013_09} Use MITK_ASSERT_NOT_EQUAL instead. * * @param OBJ1 First object. * @param OBJ2 Second object. * @param MSG Message to appear with the test. * * \sa MITK_TEST_EQUAL */ #define MITK_TEST_NOT_EQUAL(OBJ1,OBJ2,MSG) \ MITK_TEST_CONDITION_REQUIRED( mitk::Equal(OBJ1, OBJ2, mitk::eps, true)==false, MSG) +/** + * @brief Testing macro to test if two objects are not equal. + * + * @ingroup MITKTestingAPI + * + * This macro uses mitk::eps and the corresponding mitk::Equal methods for all + * comparisons and will give verbose output on the dashboard/console. + * + * @param OBJ1 First object. + * @param OBJ2 Second object. + * @param MSG Message to appear with the test. + * + * \sa MITK_ASSERT_EQUAL + */ +#define MITK_ASSERT_NOT_EQUAL(OBJ1, OBJ2, MSG) \ + CPPUNIT_ASSERT_MESSAGE(MSG, !mitk::Equal(OBJ1, OBJ2, mitk::eps, true)) + +/** + * @brief Registers the given test suite. + * + * @ingroup MITKTestingAPI + * + * @param TESTSUITE_NAME The name of the test suite class, without "TestSuite" + * at the end. + */ +#define MITK_TEST_SUITE_REGISTRATION(TESTSUITE_NAME) \ + int TESTSUITE_NAME ## Test(int /*argc*/, char* /*argv*/[]) \ + { \ + CppUnit::TextUi::TestRunner runner; \ + runner.addTest(TESTSUITE_NAME ## TestSuite::suite()); \ + runner.run(); \ + return EXIT_SUCCESS; \ + } + +/** + * @brief Adds a parameterized test to the current test suite. + * + * @ingroup MITKTestingAPI + * + * Use this macro after the CPPUNIT_TEST_SUITE() macro to add test cases + * which need parameters (e.g. from the command line). + * + * @param TESTMETHOD The name of the member function test. + */ +#define MITK_PARAMETERIZED_TEST(TESTMETHOD) \ + CPPUNIT_TEST_SUITE_ADD_TEST( \ + ( new mitk::ParameterizedTestCaller( \ + context.getTestNameFor( #TESTMETHOD), \ + &TestFixtureType::TESTMETHOD, \ + context.makeFixture() ) ) )