2010-07-22 22 views
18

अब तक, मैंने एक इम्प्रोविज्ड यूनिट परीक्षण प्रक्रिया का उपयोग किया है - मूल रूप से एक बैच फ़ाइल द्वारा स्वचालित रूप से चलने वाले यूनिट परीक्षण प्रोग्राम का एक पूरा भार। हालांकि इनमें से बहुत से अपने परिणामों की स्पष्ट रूप से जांच करते हैं, बहुत अधिक धोखा देती है - वे परिणामस्वरूप टेक्स्ट फ़ाइलों को परिणाम निकाल देते हैं। परीक्षण परिणामों में कोई भी बदलाव उपversण द्वारा ध्वजांकित हो जाता है और मैं आसानी से पहचान सकता हूं कि परिवर्तन क्या था। कई परीक्षण आउटपुट डॉट फाइल या कुछ अन्य रूप जो मुझे आउटपुट का दृश्य प्रतिनिधित्व प्राप्त करने की अनुमति देता है।मेरे यूनिट परीक्षण को सेमेक और सीटेस्ट में कैसे अनुकूलित करें?

समस्या यह है कि मैं cmake का उपयोग करने के लिए स्विच कर रहा हूं। सेमेक प्रवाह के साथ जाने का मतलब है आउट-ऑफ-सोर्स बिल्ड का उपयोग करना, जिसका अर्थ यह है कि डंपिंग की सुविधा साझा स्रोत/बिल्ड फ़ोल्डर में होती है और स्रोत के साथ उन्हें वर्जनिंग वास्तव में काम नहीं करती है।

एक प्रतिस्थापन के रूप में, मैं की तरह करने के लिए यूनिट टेस्ट टूल को बताना है कि अपेक्षित परिणामों की फाइलें (स्रोत पेड़ में) कहां मिलें और तुलना करने के लिए इसे प्राप्त करें। विफलता पर, यह वास्तविक परिणाम और diff लिस्टिंग प्रदान करना चाहिए।

क्या यह संभव है, या क्या मुझे पूरी तरह से अलग दृष्टिकोण लेना चाहिए?

जाहिर है, मैं सीटीएस्ट को अनदेखा कर सकता हूं और केवल उस स्रोत को अनुकूलित कर सकता हूं जो मैंने हमेशा स्रोत के निर्माण के लिए किया है। मैं उदाहरण के लिए (उदाहरण के लिए 'अनदेखा' के उदार उपयोग के साथ) मेरे फ़ोल्डर-जहां-सब-बिल्ड-लाइव संस्करण बना सकता हूं। क्या वह साईं है? शायद नहीं, क्योंकि प्रत्येक निर्माण अपेक्षित परिणामों की एक अलग प्रति के साथ खत्म हो जाएगा।

इसके अलावा, cmake/ctest gratefuly के साथ इकाई परीक्षण करने के अनुशंसित तरीके से कोई सलाह प्राप्त की गई। मैंने सेमीकेक के साथ काफी समय बर्बाद कर दिया, क्योंकि यह बुरा नहीं है, लेकिन क्योंकि मुझे समझ में नहीं आया कि इसके साथ कैसे काम करना है।

संपादित

अंत में, मैं यथासंभव सरल इकाई परीक्षण के cmake/ctest पक्ष रखने का फैसला किया। अपेक्षित परिणाम के विरुद्ध वास्तविक परीक्षण करने के लिए, मैं अपने पुस्तकालय में निम्नलिखित समारोह के लिए एक घर ...

bool Check_Results (std::ostream    &p_Stream , 
        const char    *p_Title , 
        const char    **p_Expected, 
        const std::ostringstream &p_Actual ) 
{ 
    std::ostringstream l_Expected_Stream; 

    while (*p_Expected != 0) 
    { 
    l_Expected_Stream << (*p_Expected) << std::endl; 
    p_Expected++; 
    } 

    std::string l_Expected (l_Expected_Stream.str()); 
    std::string l_Actual (p_Actual.str()); 

    bool l_Pass = (l_Actual == l_Expected); 

    p_Stream << "Test: " << p_Title << " : "; 

    if (l_Pass) 
    { 
    p_Stream << "Pass" << std::endl; 
    } 
    else 
    { 
    p_Stream << "*** FAIL ***" << std::endl; 
    p_Stream << "===============================================================================" << std::endl; 
    p_Stream << "Expected Results For: " << p_Title << std::endl; 
    p_Stream << "-------------------------------------------------------------------------------" << std::endl; 
    p_Stream << l_Expected; 
    p_Stream << "===============================================================================" << std::endl; 
    p_Stream << "Actual Results For: " << p_Title << std::endl; 
    p_Stream << "-------------------------------------------------------------------------------" << std::endl; 
    p_Stream << l_Actual; 
    p_Stream << "===============================================================================" << std::endl; 
    } 

    return l_Pass; 
} 

एक ठेठ इकाई परीक्षण अब तरह दिखता है ...

bool Test0001() 
{ 
    std::ostringstream l_Actual; 

    const char* l_Expected [] = 
    { 
    "Some", 
    "Expected", 
    "Results", 
    0 
    }; 

    l_Actual << "Some" << std::endl 
      << "Actual" << std::endl 
      << "Results" << std::endl; 

    return Check_Results (std::cout, "0001 - not a sane test", l_Expected, l_Actual); 
} 

मैं एक कहाँ की जरूरत है पाया पुनः उपयोग करने योग्य डेटा-डंपिंग फ़ंक्शन, यह std::ostream& प्रकार का पैरामीटर लेता है, इसलिए यह वास्तविक-परिणाम स्ट्रीम पर डंप कर सकता है।

+0

आपको इसके बजाय एक उत्तर के रूप में अपना संपादन जोड़ना चाहिए, क्योंकि यह आपके अपने प्रश्न का उत्तर देता है – Joakim

उत्तर

16

मैं परीक्षण चलाने और आउटपुट की तुलना करने के लिए सीएमके के स्टैंडअलोन स्क्रिप्टिंग मोड का उपयोग करता हूं। आम तौर पर एक यूनिट परीक्षण कार्यक्रम के लिए, आप add_test(testname testexecutable) लिखेंगे, लेकिन आप किसी भी कमांड को परीक्षण के रूप में चला सकते हैं।

यदि आप "runtest.cmake" स्क्रिप्ट लिखते हैं और इसके माध्यम से अपना यूनिट परीक्षण प्रोग्राम निष्पादित करते हैं, तो runtest.cmake स्क्रिप्ट इसे पसंद कर सकती है - cmake -E compare_files उपयोगिता का उपयोग कर। आप अपने CMakeLists.txt फ़ाइल में निम्न की तरह कुछ हैं:

enable_testing() 
add_executable(testprog main.c) 
add_test(NAME runtestprog 
    COMMAND ${CMAKE_COMMAND} 
    -DTEST_PROG=$<TARGET_FILE:testprog> 
    -DSOURCEDIR=${CMAKE_CURRENT_SOURCE_DIR} 
    -P ${CMAKE_CURRENT_SOURCE_DIR}/runtest.cmake) 

यह एक स्क्रिप्ट रन (cmake -पी runtest.cmake) और 2 चर परिभाषित करता है: TEST_PROG, परीक्षण निष्पादन के पथ पर सेट है, और SOURCEDIR , वर्तमान स्रोत निर्देशिका पर सेट करें। आपको यह जानने के लिए पहले कौन सा प्रोग्राम चलाने की जरूरत है, दूसरा यह जानने के लिए कि अपेक्षित परीक्षा परिणाम फाइल कहां मिलें।runtest.cmake की सामग्री को होगा:

execute_process(COMMAND ${TEST_PROG} 
       RESULT_VARIABLE HAD_ERROR) 
if(HAD_ERROR) 
    message(FATAL_ERROR "Test failed") 
endif() 

execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files 
    output.txt ${SOURCEDIR}/expected.txt 
    RESULT_VARIABLE DIFFERENT) 
if(DIFFERENT) 
    message(FATAL_ERROR "Test failed - files differ") 
endif() 

पहले execute_process परीक्षण कार्यक्रम है, जो बाहर "output.txt" लिखेंगे चलाता है। यदि यह काम करता है, तो अगला execute_process प्रभावी रूप से cmake -E compare_files output.txt expected.txt चलाता है। फ़ाइल "expected.txt" आपके स्रोत पेड़ में ज्ञात अच्छा परिणाम है। यदि मतभेद हैं, तो यह त्रुटियों से बाहर निकलता है ताकि आप असफल परीक्षण देख सकें।

यह क्या नहीं करता अंतरों को प्रिंट करना है; सीएमके के पास एक पूर्ण "diff" कार्यान्वयन नहीं है जो इसके भीतर छिपा हुआ है। फिलहाल आप सबवर्सन का उपयोग देखने के लिए लाइनों क्या बदल गया है, तो एक स्पष्ट समाधान के लिए अंतिम भाग बदलने के लिए है:

if(DIFFERENT) 
    configure_file(output.txt ${SOURCEDIR}/expected.txt COPYONLY) 
    execute_process(COMMAND svn diff ${SOURCEDIR}/expected.txt) 
    message(FATAL_ERROR "Test failed - files differ") 
endif() 

इस विफलता पर निर्माण उत्पादन के साथ स्रोत पेड़ अधिलेखित कर देता है तो उस पर diff SVN चलाता है। समस्या यह है कि आपको वास्तव में इस तरह स्रोत पेड़ को बदलना नहीं चाहिए। जब आप दूसरी बार परीक्षण चलाते हैं, तो यह गुजरता है! एक बेहतर तरीका कुछ दृश्य diff उपकरण स्थापित करना है और इसे अपने आउटपुट और अपेक्षित फ़ाइल पर चलाएं।

+0

बहुत करीब लगता है, और निश्चित रूप से जानकारीपूर्ण - धन्यवाद। बीटीडब्लू - "परीक्षण फिर से चलाएं और यह गुजरता है" मुद्दा वास्तव में मौजूद नहीं है। यदि परीक्षण विफल हो रहा है, तो मैं वर्तमान गलत परिणामों को नए अपेक्षित परिणामों के रूप में प्रतिबद्ध करने के लिए पर्याप्त नहीं हूं। मैं चाहता हूं कि diff कामकाजी प्रतिलिपि और सिर संस्करणों के बीच है। फिर भी, निर्माण के पेड़ में वास्तविक परिणाम रखने के लिए यह समझ में आता है, और किसी अन्य प्रोग्राम का उपयोग करके भिन्नता है, इसलिए कार्यशील प्रतिलिपि नहीं बदली गई है। "मैं उस गलती को करने के लिए पर्याप्त दिक्कत नहीं कर रहा हूं" प्रलोभन भाग्य की तरह थोड़ा प्रतीत होता है। – Steve314

+0

मैंने अतीत में भी क्या किया है (हालांकि यह अधिक लाभ के लिए अधिक काम नहीं था) परीक्षण कार्यक्रम के परिणाम उत्पन्न करना था और उन्हें ज्ञात अच्छे परिणामों के खिलाफ भी जांचना था। मैंने बिल्ड पेड़ में अपेक्षित परिणाम प्राप्त करने के लिए 'config_file (अपेक्षित.dat.in अपेक्षित.dat कॉपीराइट) का उपयोग किया। इस तरह से परीक्षण कह सकता है "आह! आपको एक समस्या है जो 163 वें प्रविष्टि से शुरू होती है!", इसके बाद एक अंतर चलाने के बजाए। – richq

+0

मैं "किकस्टार्टिंग" सी ++ परियोजनाओं के लिए [सीएमके फ्रेमवर्क] (http://jaws.rootdirectory.de) पर काम कर रहा हूं। इसे [सीसी 0] (http://creativecommons.org/publicdomain/zero/1.0/) के रूप में लाइसेंस प्राप्त किया जा रहा है, जबकि स्टैक ओवरफ्लो का लाइसेंस सीसी बाई-एस है। अगर मैं पूर्ण क्रेडिट देकर सीसी 0 शर्तों के तहत अपना समाधान अनुकूलित करता हूं तो क्या यह आपके साथ ठीक रहेगा? – DevSolar