2010-07-22 13 views
18

Cho đến bây giờ, tôi đã sử dụng một thủ tục kiểm tra đơn vị ngẫu hứng - về cơ bản một tải toàn bộ các chương trình thử nghiệm đơn vị chạy tự động bởi một tập tin thực thi. Mặc dù rất nhiều trong số này rõ ràng kiểm tra kết quả của họ, nhiều gian lận hơn - họ kết xuất ra các tập tin văn bản được phiên bản. Bất kỳ thay đổi nào trong kết quả kiểm tra đều bị gắn cờ bởi subversion và tôi có thể dễ dàng xác định thay đổi đó là gì. Nhiều người trong số các bài kiểm tra đầu ra các tập tin dot hoặc một số hình thức khác cho phép tôi để có được một đại diện trực quan của đầu ra.Làm cách nào để điều chỉnh các thử nghiệm đơn vị của tôi thành cmake và ctest?

Sự cố là tôi đang chuyển sang sử dụng cmake. Đi với luồng cmake có nghĩa là sử dụng các bản dựng ngoài nguồn, có nghĩa là sự tiện lợi của việc kết xuất các kết quả trong một thư mục nguồn/chia sẻ được chia sẻ và phiên bản chúng cùng với nguồn không thực sự hoạt động. Là một sự thay thế, những gì tôi muốn như để làm là để cho công cụ kiểm tra đơn vị nơi để tìm tập tin kết quả mong đợi (trong cây nguồn) và làm cho nó để làm so sánh. Khi thất bại, nó sẽ cung cấp kết quả thực tế và danh sách khác.

Điều này có thể hay tôi nên thực hiện một cách tiếp cận hoàn toàn khác?

Rõ ràng, tôi có thể bỏ qua ctest và chỉ chỉnh sửa những gì tôi đã luôn thực hiện đối với các bản dựng ngoài nguồn. Tôi có thể phiên bản thư mục của tôi-nơi-tất cả-các-xây dựng-sống, ví dụ (với việc sử dụng tự do của 'bỏ qua' tất nhiên). Có lành không? Có lẽ không, vì mỗi bản dựng sẽ kết thúc với một bản sao riêng biệt của các kết quả mong đợi.

Ngoài ra, bất kỳ lời khuyên nào về cách được khuyến nghị để thực hiện kiểm tra đơn vị với nhận biết về cmake/ctest đã nhận được. Tôi lãng phí một chút thời gian công bằng với cmake, không phải vì nó xấu, nhưng bởi vì tôi không hiểu cách tốt nhất để làm việc với nó.

EDIT

Cuối cùng, tôi quyết định giữ nguyên cmake/bên ctest của kiểm tra đơn vị như đơn giản càng tốt. Để kiểm tra thực tế chống lại kết quả mong đợi, tôi thấy một ngôi nhà cho các chức năng sau đây trong thư viện của tôi ...

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; 
} 

Một thử nghiệm đơn vị điển hình bây giờ trông giống như ...

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); 
} 

Nơi tôi cần một chức năng bán phá giá dữ liệu có thể sử dụng lại, nó có tham số kiểu std::ostream&, do đó, nó có thể đổ vào luồng kết quả thực tế.

+0

Thay vào đó, bạn nên thêm Chỉnh sửa làm câu trả lời vì câu trả lời cho câu hỏi của riêng bạn – Joakim

Trả lời

16

Tôi muốn sử dụng chế độ tập lệnh độc lập của CMake để chạy thử nghiệm và so sánh kết quả đầu ra. Thông thường đối với một chương trình thử nghiệm đơn vị, bạn sẽ viết add_test(testname testexecutable), nhưng bạn có thể chạy bất kỳ lệnh nào dưới dạng thử nghiệm.

Nếu bạn viết một tập lệnh "runtest.cmake" và thực hiện chương trình thử nghiệm đơn vị của bạn thông qua điều này, thì tập lệnh runtest.cmake có thể làm bất cứ điều gì nó thích - bao gồm sử dụng tiện ích cmake -E compare_files. Bạn muốn một cái gì đó như sau trong tập tin CMakeLists.txt của bạn:

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) 

này chạy một kịch bản (cmake -P runtest.cmake) và định nghĩa 2 biến: TEST_PROG, thiết lập để đường dẫn của bài kiểm tra thực thi, và SourceDir , được đặt thành thư mục nguồn hiện tại. Bạn cần đầu tiên biết chương trình nào để chạy, chương trình thứ hai để biết nơi tìm các tệp kết quả thử nghiệm dự kiến.Nội dung của runtest.cmake sẽ là:

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() 

Đầu tiên execute_process chạy chương trình kiểm tra, mà sẽ viết ra "output.txt". Nếu cách đó hoạt động, thì execute_process chạy tiếp theo có hiệu quả cmake -E compare_files output.txt expected.txt. Tệp "expected.txt" là kết quả tốt được biết đến trong cây nguồn của bạn. Nếu có sự khác biệt, nó sẽ bị lỗi để bạn có thể thấy bài kiểm tra không thành công.

Điều này không làm là in ra sự khác biệt; CMake không thực hiện đầy đủ "diff" ẩn bên trong nó. Tại thời điểm này bạn sử dụng Subversion để xem những gì dòng đã thay đổi, vì vậy một giải pháp rõ ràng là thay đổi phần cuối cùng để:

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() 

này ghi đè cây nguồn với việc xây dựng đầu ra về thất bại sau đó chạy svn diff trên đó. Vấn đề là bạn không nên thực sự thay đổi cây nguồn theo cách này. Khi bạn chạy thử nghiệm lần thứ hai, nó sẽ vượt qua! Cách tốt hơn là cài đặt một số công cụ tìm khác biệt trực quan và chạy công cụ đó trên đầu ra của bạn và tệp được mong đợi.

+0

Âm thanh khá gần và chắc chắn - thông tin. BTW - "chạy thử nghiệm một lần nữa và nó vượt qua" vấn đề không thực sự tồn tại. Nếu thử nghiệm thất bại, tôi không đủ daft để cam kết kết quả sai hiện tại như kết quả mong đợi mới. Các diff tôi muốn là giữa các bản sao làm việc và các phiên bản đầu. Mặc dù vậy, nó có ý nghĩa để giữ kết quả thực tế trong cây xây dựng, và làm khác bằng cách sử dụng một chương trình khác, do đó, bản sao làm việc không thay đổi. "Tôi không đủ ngu ngốc để phạm phải sai lầm đó" dường như hơi giống với số phận hấp dẫn. – Steve314

+0

Những gì tôi cũng đã làm trong quá khứ (mặc dù nó đã được nhiều công việc vì lợi ích không nhiều hơn) là có chương trình thử nghiệm tạo ra kết quả của nó và cũng kiểm tra chúng chống lại các kết quả tốt được biết đến. Tôi đã sử dụng 'config_file (expected.dat.in expected.dat COPYONLY)' để lấy kết quả mong muốn được sao chép vào cây xây dựng. Bằng cách này thử nghiệm có thể nói "eh! Bạn đã có một vấn đề mà bắt đầu tại mục 163!", Thay vì phải chạy một diff sau đó. – richq

+0

Tôi đang làm việc trên [Khung công tác CMake] (http://jaws.rootdirectory.de) cho các dự án "khởi động" C++. Điều đó đang được cấp phép dưới dạng [CC0] (http://creativecommons.org/publicdomain/zero/1.0/), trong khi giấy phép StackOverflow là CC by-sa. Bạn có thể đồng ý với tôi nếu tôi đã điều chỉnh giải pháp của bạn theo các điều khoản của CC0 trong khi đưa ra toàn bộ tín dụng? – DevSolar

Các vấn đề liên quan