2013-06-17 2 views
3

모호함으로 인해 응용 프로그램이 다운되지 않도록하려는 클래스 멤버가 있습니다.boost.Test를 사용하여 catch 블록을 시도하십시오.

void getGene(unsigned int position){ 
    T val; 
    try { 
     val = _genome.at(_isCircular ? position % _genome.size() : position); 
    } 
    catch (std::exception& e) { 
     std::cerr << "Error in [" << __PRETTY_FUNCTION__ << "]: " 
        << e.what() << std::endl; 
     exit(1); 
    } 
    return val; 
} 

지금, 내가

BOOST_AUTO_TEST_CASE(nonCircularGenome_test){ 

    // set size to 10 
    test.setSize(10); 
    // set non circular 
    test.setNonCircular();  

    // gene at site # 12 does not exist in a 10-site long genome, must throw an exception 
    BOOST_CHECK_THROW(test.getGene(12), std::out_of_range); 
문제가

같은 일을 생각 부스트 단위 테스트를 추가하려면, 아래 그림과 같이 그 목적을 위해 나는 시도 캐치 복을 추가 한 나는이 두 가지 일을 모두 할 수 없다. try-catch 블록은 릴리즈 설정에서 잘 작동합니다. 그러나이 테스트는 try-catch 블록을 제거하고 함수가 예외를 throw하도록하는 경우에만 작동합니다.

두 가지 모두 작동하도록하는 가장 좋은 방법은 무엇입니까? 디버그에서 테스트가 명시 적으로 확인되는 동안 사용자가 이동 중에 올바른 오류 메시지가 표시되도록하려면 어떻게해야합니까? 한 가지 방법은 # ifdef/#endif DEBUG 블록을 사용하는 것이지만 프리 프로세서 매크로는 피하고 싶습니다. 사전에

감사합니다,

Nikhil

답변

3

당신은 예외의 범위와 목적을 오해하는 것 - 오류는 일반적으로 처리 아마의.

먼저 함수의 사전 조건을 정의해야합니다. getGene()은 항상 position이 유효한 것으로 간주합니까? 그것의 클라이언트가 결코는 유효하지 않은 위치를 제공 할 것으로 기대합니까?

이 경우 클라이언트가 테스트 루틴 인 경우에도 잘못된 위치를 제공하는 클라이언트는 getGene() (특히 사전 조건 위반)으로 계약을 위반하고 계약은 정의에 의해 정의되지 않은 동작입니다. 정의되지 않은 동작을 테스트 할 수 없으므로 테스트를 제거해야합니다.

반면에 함수에 넓은 계약이있는 경우 클라이언트가 의 위치 (심지어 유효하지 않은 위치)에 전달할 수 있고 (a) 예외를 throw하거나 (b)에 오류 코드를 반환 할 수 있습니다. 위치가 유효하지 않을 때 실패를 알리는 경우, 프로그램을 종료하고 제어가 발신자에게 다시 전송되지 않기 때문에 exit(1) 행이 없어야합니다.

하나의 가능성은 로그인 한 후에 예외를 다시 던질 수있는 진단 :

T getGene(unsigned int position){ 
    T val; 
    try { 
     val = _genome.at(_isCircular ? position % _genome.size() : position); 
    } 
    catch (std::exception& e) { 
     std::cerr << "Error in [" << __PRETTY_FUNCTION__ << "]: " 
        << e.what() << std::endl; 

     throw; 
//  ^^^^^ 
    } 
    return val; 
} 

그리고 당신은 진단을 인쇄 할 필요가없는 경우, 다만 예외가 자연스럽게 전파하자

T getGene(unsigned int position){ 
    return _genome.at(_isCircular ? position % _genome.size() : position); 
} 
+0

+ 1,하지만 몇 가지 세부 사항 ... * 때로는 정의되지 않은 동작을 테스트 할 수 있습니다.이 동작은 정의되지 않은 동작에 따라 달라집니다. Lakos 용어로는 정의되지 않은 동작 (즉, 라이브러리에 대한 계약 요청이 끊긴 상태)을 테스트 할 수 있지만 하드 및 정의되지 않은 동작 (예 : 라이브러리 및/또는 언어에서 이미 정의되지 않은 동작을 트리거 한 동작)은 테스트 할 수 없습니다. 실제로 이에 대한 지원을 추가하는 제안 ([n3604] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3604.pdf))이 있습니다. 언어 수준 및 [BSL] (https://github.com/bloomberg/bsl)에는 라이브러리 수준 구현이 있습니다. –

+0

@ DavidRodríguez-dribeas : 나는 그 내용을 정확히 기억하기 위해 그 재미있는 제안을 너무 오래 전에 읽은 것을 고백해야합니다.이제 약간 의아해하니 마음에 들지 않는지 물어볼 것입니다 : 사전 조건을 위반하는 것이 정의되지 않은 행동 인 경우 해당 조건을 위반하여 해당 함수를 호출하면 정의되지 않은 동작이 트리거 될 것입니다. 테스트 주장은 일관된 결과를 기대할 수 없습니다. 내가 이것을 오해하고 있는가? 또는 우리의 테스트는 정상적으로 정의되지 않은 동작이 잘 정의 된 동작 (예 : 예외 발생) 인 상황에서 실행되어야합니까? –

+0

요점은 함수에서 어설 션 매크로 중 하나를 사용하여 함수 자체가 정의되지 않은 동작을 일으키는 전제 조건을 테스트 할 수 있다는 것입니다. 블룸버그/BSL의 프레임 워크와 제안은 어설 션이 '메인'(어떤 경우에도 코드의 단일 지점에서)에서 트리거 될 때 일어나는 일의 구성을 가능하게합니다. 이제 테스트 스위트 (BSL 테스트를 확인할 수 있음)에서 어설 션 핸들러를 고유 한 예외로 구성 할 수 있으며 그런 식으로 자신의 인터페이스에서 코드가 * UB를 감지 할 수 있는지 확인하는 테스트를 추가 할 수 있습니다. ..] –