2012-10-04 6 views
1

저는 C++의 자동 단위 테스트의 초보자입니다. 나는 boost :: unit_test의 지시를 따르고 boost :: unit_test에서 함수 unit_test_main을 호출하여 테스트 계획을 마쳤다. 테스트 프로그램을 실행하는 데 아무런 문제가 없습니다. 그러나 테스트 함수에 인수를 전달하는 데 문제가 있습니다. 어쩌면, 다음과 같은 코드가 훨씬 더 내 문제를 설명 할 수boost :: unit_test로 자동 테스트를 수행하는 스크립트를 작성하는 방법은 무엇입니까?

#ifndef MAIN_CPP_ 
#define MAIN_CPP_ 



#include <string> 
#include <vector> 
#include <iostream> 
#include <assert.h> 

#include <boost/program_options.hpp> 
#include <boost/test/test_tools.hpp> 
#include <boost/test/execution_monitor.hpp> 
#include <boost/test/unit_test.hpp> 




using namespace boost::program_options; 
using namespace std; 
using namespace boost; 
using namespace boost::unit_test; 




/** 
* the global test suite 
*/ 

boost::unit_test::test_suite* get_feelfree_test_suite(); 
boost::unit_test::test_suite* main_global_test_suite; 

/** 
* name of the test suite 
*/ 
std::string current_global_test_suite_name; 

#ifdef BOOST_TEST_ALTERNATIVE_INIT_API 

bool run_global_test_suite() { 
    boost::unit_test::test_suite& masterTestSuite = framework::master_test_suite(); 

    if(masterTestSuite.size() != 0) { 
     test_unit_id formerTestSuite = masterTestSuite.get(current_global_test_suite_name); 
     masterTestSuite.remove(formerTestSuite); 

    } 
    masterTestSuite.add(main_global_test_suite); 
    current_global_test_suite_name = main_global_test_suite->p_name.get(); 

    return true; 
} 
#else 
    test_suite* run_global_test_suite(int, char* []) { 
    return main_global_test_suite; 
} 
#endif 

/** 
* Obtain test program options 
*/ 
int obtain_options(char **optionLine, int argc, char** argv); 





/** 
* This function is used to run the test program, and the procedure is really standard. 
*/ 
int main(int argc, char* argv[]) 
{ 
    try 
    { 
     /** 
     * Step 1. obtain options 
     */ 
     char* optionLine[1024]; 
     int len ; 
     len = obtain_options(optionLine, argc, argv); 
     /** 
     * Step 2. perform unit test based on user's options 
     */ 
     int test_status=0; 
     main_global_test_suite = get_feelfree_test_suite(); 
     test_status = unit_test_main(run_global_test_suite, len, optionLine); 
     return test_status; 
    } 
    catch(std::exception& e) 
    { 
     std::cout << e.what() << std::endl; 
     return 1; 
    } 
    catch (const std::string& s) 
    { 
     std::cout << s << std::endl; 
     return 1; 
    } 
    catch (...) 
    { 
     return 1; 
    } 


} 
/** @} */ 


int obtain_options(char **optionLine, int argc, char* argv[]) 
{ 
    // 1. All the options for testing the program 
     options_description desc("Allowed options"); 
     desc.add_options()("help", "produce help message") 
     ("detect_memory_leaks", value<bool>()->default_value(false), "test configuration option (option of boost framework)"); 
     // 2. Perform parsing 
     variables_map vm; 
     store(parse_command_line(argc, argv, desc), vm); 
     notify(vm); 
     // 3. Illustrate the input 
     std::vector<const char*> options; 
     std::string testSuiteToRun; 
     if(vm.count("test_suite")){ 
      testSuiteToRun = vm["test_suite"].as<string>(); 
     } 
     else { 
      testSuiteToRun = "main"; 
     } 

     options.push_back(argv[0]); 
     if(vm.count("detect_memory_leaks")) { 
      bool detect = vm["detect_memory_leaks"].as<bool>(); 
      if(detect) { 
       options.push_back("--detect_memory_leaks=1"); 
      } 
      else { 
      options.push_back("--detect_memory_leaks=0"); 
      } 
     } 
     else { 
      options.push_back("--detect_memory_leaks=0"); 
     } 

     // 4. Obtain all the parameters in the format of char** 

     assert(options.size() < 1024); 
     std::copy(options.begin(), options.end(), const_cast<const char**>(optionLine)); 

     return options.size(); 

} 

void Testsub(const std::string &name) 
{ 
    cout<<"File_name: "<<name<<endl; 
} 
void Testabc() 
{ 
    std::vector<std::string > name_array; 
    name_array.push_back("name 1"); 
    name_array.push_back("name 2"); 
    for(int i=0; i<name_array.size(); i++) 
     Testsub(name_array[i]); 
} 


boost::unit_test::test_suite* get_feelfree_test_suite() 
{ 
    test_suite* ts = BOOST_TEST_SUITE("unit_geometric"); 
    ts->add(BOOST_TEST_CASE(&Testabc)); 
    return ts; 
} 


#endif 

당신은이 테스트 프레임 워크에, 내가 테스트 할 주요 기능은 입력 인수 CONST의 표준에 의존 Testsub, 입니다 볼 수 있듯이 :: 문자열 & 이름. 그러나 테스트 스위트 함수 get_feelfree_test_suite을 통해 인수를 전달할 수 없습니다. 따라서이 테스트 프로그램에서는 다른 테스트 기능을 작성했습니다 Testabc, 가능한 모든 파일 테스트 목록이 제공되어 Testsub으로 전달됩니다. 이것은 분명히 최선의 해결책은 아닙니다. 다른 솔루션이 있는지 궁금합니다. 몇 가지 솔루션은 내 마음에 있지만 나는 그들이 좋은 솔루션입니다 여부를 알 수 없습니다 :

  • 해결 방법 1 : 주요 기능 (int main(int argc, char* argv[])에서 get_feelfree_test_suite에 인수를 전달하는 방법을 알아보십시오. 그 후, 스크립트를 작성하여 번 프로그램을 여러 번 실행하십시오. 창에서 가능한 스크립트는 .bat 스크립트입니다. 의 경우이 솔루션을 구현하는 방법을 모르겠습니다.
  • 해결 방법 2 : 가능한 모든 입력 파일 이름이 주어진 목록 파일을 작성한 다음 프로그램의 목록 파일을 읽으십시오. 이것은 구현하기가 훨씬 쉽습니다.

또한 파이썬이 테스트 프레임 워크에 매우 쉽게 통합 될 수 있다고 들었지만, 그것에 대해서는 전혀 모른다. 어쨌든, 나는 모든 가능한 해결책에 열려 있으며, 고마워!

+0

Testsub와 같은 간단한 기능의 경우이 테스트 프로그램이 약간 복잡해 보입니다.왜 BOOST_AUTO_TEST_CASE를 사용하지 않으시겠습니까? – Sebastian

답변

0

정말 다른 파일에 다른 "이름"이 있어야합니까? 테스트 스위트에 넣는 것이 더 쉽습니다. 모든 이름에 대해 하나의 BOOST_AUTO_TEST_CASE. 또는 테스트 케이스에서 반복 할 수있는 이름의 배열.

0

모든 코드의 목적을 이해하지 못했기 때문에 명령 행에서 -F file1 -F file2과 같은 요소를 구문 분석하여 작업을 수행하는 최소 샘플을 게시합니다 (Testsub 여러 번 호출).

#include <boost/test/parameterized_test.hpp> 
//... 
void Testsub(const std::string &name) 
{ 
    cout<<"File_name: "<<name<<endl; 
} 
test_suite* init_unit_test_suite(int argc, char* argv[]) 
{ 
    std::vector<std::string> files_to_run_local; 

    for(int i = 0; i < framework::master_test_suite().argc; i++) 
    { 
    if(std::string(framework::master_test_suite().argv[i]) == "-F") 
    { 
     if(i == framework::master_test_suite().argc - 1) 
     { 
     std::cerr << "Error in the command line" << std::endl; 
     throw boost::unit_test::framework::setup_error("Error in the command line"); 
     } 
     files_to_run_local.push_back(framework::master_test_suite().argv[++i]); 
    } 
    } 

    test_suite* ts = BOOST_TEST_SUITE("unit_geometric"); 
    ts->add(BOOST_PARAM_TEST_CASE(&Testsub, 
            files_to_run_local.begin(), 
            files_to_run_local.end())); 

    framework::master_test_suite().add(ts); 

    return 0; 
} 

지금, 나는 당신이 단위 테스트 프레임 워크로 파일 목록을 전달하는 데 사용 된 방법을 통해 결정하는 하나의 생각 : 그것은 boost::unittestBOOST_PARAM_TEST_CASE 매크로를 사용한다. 모든 파일을 포함하는 파일도 좋은 해결책이 될 수 있으며 전달할 목록이 크면 중간 파일을 사용하는 단점이 있습니다.

그러나이 질문에 대한 답은 실제로 어떤 프레임 워크가 테스트 (cmake, shell 등)를 실행하는지에 달려 있습니다. Python/cmake는 명령 행이나 중간 파일을 매우 쉽게 생성 할 수 있습니다.

모든 경우에 정리 메서드는 BOOST_PARAM_TEST_CASE 매크로를 호출하는 것입니다.